Spring 框架基础(04):AOP切面编程概念,几种实现方式演示
本文源码:GitHub·点这里 || GitEE·点这里
一、AOP基础简介
1、切面编程简介
AOP全称:Aspect Oriented Programming,面向切面编程。通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。核心作用:可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的复用性和开发效率。AOP提供了取代继承和委托的一种新的方案,而且使用起来更加简洁清晰,是软件开发中的一个热点理念。
2、AOP术语
(1)、通知类型:Advice
前置通知[Before]:目标方法被调用之前;
返回通知[After-returning]:目标方法执行成功之后;
异常通知[After-throwing]:在目标方法抛出异常之后;
后置通知[After]:目标方法完成之后;
环绕通知[Around]:在目标方法执行前后环绕通知;
(2)、连接点:JoinPoint
程序执行的某一个特定位置,如类初始前后,方法的运行前后。
(3)、切点:Pointcut
连接点是指那些在指定策略下可能被拦截到的方法。
(4)、切面:Aspect
切面由切点和通知的结合。
(5)、引入:Introduction
特殊的增强,为类添加一些属性和方法。
(6)、织入:Weaving
将增强添加到目标类的具体连接点上的过程。编译期织入,这要求使用特殊编译器;类装载期织入,这要求使用特殊的类加载器;动态代理织入,在运行期为目标类添加增强生成子类的方式,Spring采用的是动态代理织入,而AspectJ采用编译期织入和类装载期织入。
(7)、代理:Proxy
类被AOP织入后生成一个结果类,它是融合了原类和增强逻辑的代理类。
二、AOP编程实现方式
案例基于如下类进行:
public class Book {
private String bookName ;
private String author ;
}
public interface BookService {
void addBook (Book book) ;
}
public class BookServiceImpl implements BookService {
@Override
public void addBook(Book book) {
System.out.println(book.getBookName());
System.out.println(book.getAuthor());
}
}
1、JDK动态代理
public class BookAopProxyFactory {
public static BookService createService() {
// 目标类
final BookService bookService = new BookServiceImpl() ;
// 切面类
final BookAspect bookAspect = new BookAspect();
/*
* 代理类:将目标类(切入点)和 切面类(通知) 结合
*/
BookService proxyBookService = (BookService) Proxy.newProxyInstance(
BookAopProxyFactory.class.getClassLoader(),
bookService.getClass().getInterfaces(),
new InvocationHandler() {
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
// 前执行
bookAspect.before();
// 执行目标类的方法
Object obj = method.invoke(bookService, args);
// 后执行
bookAspect.after();
return obj;
}
});
return proxyBookService ;
}
}
2、CgLib字节码增强
采用字节码增强框架cglib,在运行时创建目标类的子类,从而对目标类进行增强。
public class BookAopCgLibFactory {
public static BookService createService() {
// 目标类
final BookService bookService = new BookServiceImpl() ;
// 切面类
final BookAspect bookAspect = new BookAspect();
// 核心代理类
Enhancer enhancer = new Enhancer();
// 确定父类
enhancer.setSuperclass(bookService.getClass());
// 设置回调函数
enhancer.setCallback(new MethodInterceptor() {
public Object intercept(Object proxy, Method method,
Object[] args,
MethodProxy methodProxy) throws Throwable {
bookAspect.before();
Object obj = method.invoke(bookService, args);
bookAspect.after();
return obj;
}
});
BookServiceImpl proxyService = (BookServiceImpl) enhancer.create();
return proxyService ;
}
}
3、Spring半自动代理
spring 创建代理对象,从spring容器中手动的获取代理对象。
- 配置文件
<!-- 创建目标类 -->
<bean id="bookService" class="com.spring.mvc.service.impl.BookServiceImpl" />
<!-- 创建切面类 -->
<bean id="myAspect" class="com.spring.mvc.config.BookAopSpringHalf" />
<!-- 创建代理类 -->
<bean id="proxyFactory" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interfaces" value="com.spring.mvc.service.BookService" />
<property name="target" ref="bookService" />
<property name="interceptorNames" value="myAspect" />
</bean>
- 切面类
public class BookAopSpringHalf implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
System.out.println("Method Before ...");
Object obj = methodInvocation.proceed();
System.out.println("Method After ...");
return obj;
}
}
4、Spring全自动代理
从spring容器获得目标类,如果配置Aop,spring将自动生成代理。
- 配置文件
<!-- 创建目标类 -->
<bean id="bookService" class="com.spring.mvc.service.impl.BookServiceImpl" />
<!-- 创建切面类 -->
<bean id="myAspect" class="com.spring.mvc.config.BookAopSpringHalf" />
<!-- AOP编程配置 -->
<aop:config proxy-target-class="true">
<aop:pointcut expression="execution(* com.spring.mvc.service.*.*(..))"
id="myPointCut"/>
<aop:advisor advice-ref="myAspect" pointcut-ref="myPointCut"/>
</aop:config>
5、综合测试
@Test
public void test1 (){
BookService bookService = BookAopProxyFactory.createService() ;
Book book = new Book() ;
book.setBookName("Spring实战");
book.setAuthor("Craig Walls");
bookService.addBook(book);
}
@Test
public void test2 (){
BookService bookService = BookAopCgLibFactory.createService() ;
Book book = new Book() ;
book.setBookName("MySQL");
book.setAuthor("Baron");
bookService.addBook(book);
}
@Test
public void test3 (){
String xmlPath = "spring-aop-half.xml";
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(xmlPath);
BookService bookService = (BookService) context.getBean("proxyFactory");
Book book = new Book() ;
book.setBookName("红楼梦");
book.setAuthor("曹雪芹");
bookService.addBook(book);
}
@Test
public void test4 (){
String xmlPath = "spring-aop-all.xml";
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(xmlPath);
BookService bookService = (BookService) context.getBean("bookService");
Book book = new Book() ;
book.setBookName("西游记");
book.setAuthor("吴承恩");
bookService.addBook(book);
}
三、AspectJ切面编程
1、基础简介
AspectJ是一个基于Java语言的AOP框架,Spring2.0以后新增了对AspectJ切点表达式支持,通过JDK5注解技术,允许直接在类中定义切面,新版本Spring框架,推荐使用AspectJ方式来开发AOP编程。
2、XML配置方式
- 切面类
public class BookAopAspectJ {
public void myBefore(JoinPoint joinPoint){
System.out.println("前置通知:" + joinPoint.getSignature().getName());
}
public void myAfterReturning(JoinPoint joinPoint,Object ret){
System.out.println("后置通知:" + joinPoint.getSignature().getName() + " , -->" + ret);
}
public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("环绕通知前");
Object obj = joinPoint.proceed();
System.out.println("环绕通知前后");
return obj;
}
public void myAfterThrowing(JoinPoint joinPoint,Throwable e){
System.out.println("抛出异常通知 : " + e.getMessage());
}
public void myAfter(JoinPoint joinPoint){
System.out.println("最终通知");
}
}
- 配置文件
<!-- 创建目标类 -->
<bean id="bookService" class="com.spring.mvc.service.impl.BookServiceImpl" />
<!-- 创建切面类 -->
<bean id="myAspect" class="com.spring.mvc.config.BookAopAspectJ" />
<!-- 配置AOP编程 -->
<aop:config>
<aop:aspect ref="myAspect">
<aop:pointcut expression="execution(* com.spring.mvc.service.impl.BookServiceImpl.*(..))" id="myPointCut"/>
<!-- 前置通知-->
<aop:before method="myBefore" pointcut-ref="myPointCut"/>
<!-- 后置通知 -->
<aop:after-returning method="myAfterReturning" pointcut-ref="myPointCut" returning="ret" />
<!-- 环绕通知 -->
<aop:around method="myAround" pointcut-ref="myPointCut"/>
<!-- 抛出异常 -->
<aop:after-throwing method="myAfterThrowing" pointcut-ref="myPointCut" throwing="e"/>
<!-- 最终通知 -->
<aop:after method="myAfter" pointcut-ref="myPointCut"/>
</aop:aspect>
</aop:config>
- 测试方法
@Test
public void test1 (){
String xmlPath = "spring-aop-aspectj-01.xml";
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(xmlPath);
BookService bookService = (BookService) context.getBean("bookService");
Book book = new Book() ;
book.setBookName("三国演义");
book.setAuthor("罗贯中");
bookService.addBook(book);
}
3、注解扫描方式
- 配置文件
<!-- 开启类注解的扫描 -->
<context:component-scan base-package="com.spring.mvc.service.impl" />
<!-- 确定AOP注解生效 -->
<aop:aspectj-autoproxy />
<!-- 声明切面 -->
<bean id="myAspect" class="com.spring.mvc.config.AuthorAopAspectJ" />
<aop:config>
<aop:aspect ref="myAspect" />
</aop:config>
- 注解切面类
@Component
@Aspect
public class AuthorAopAspectJ {
@Pointcut("execution(* com.spring.mvc.service.impl.AuthorServiceImpl.*(..))")
private void myPointCut(){
}
@Before("execution(* com.spring.mvc.service.impl.AuthorServiceImpl.*(..))")
public void myBefore(JoinPoint joinPoint){
System.out.println("前置通知:" + joinPoint.getSignature().getName());
}
@AfterReturning(value="myPointCut()" ,returning="ret")
public void myAfterReturning(JoinPoint joinPoint,Object ret){
System.out.println("后置通知:" +
joinPoint.getSignature().getName() + " , -->" + ret);
}
@Around(value = "myPointCut()")
public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("环绕通知前");
Object obj = joinPoint.proceed();
System.out.println("环绕通知前后");
return obj;
}
@AfterThrowing(
value="execution(* com.spring.mvc.service.impl.AuthorServiceImpl.*(..))",
throwing="e")
public void myAfterThrowing(JoinPoint joinPoint,Throwable e){
System.out.println("抛出异常通知 : " + e.getMessage());
}
@After("myPointCut()")
public void myAfter(JoinPoint joinPoint){
System.out.println("最终通知");
}
}
- 测试方法
@Test
public void test2 (){
String xmlPath = "spring-aop-aspectj-02.xml";
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(xmlPath);
AuthorService authorService = (AuthorService) context.getBean("authorService");
System.out.println("作者:"+authorService.getAuthor());
}
四、源代码地址
GitHub·地址
https://github.com/cicadasmile/spring-mvc-parent
GitEE·地址
https://gitee.com/cicadasmile/spring-mvc-parent
Spring 框架基础(04):AOP切面编程概念,几种实现方式演示的更多相关文章
- Spring 框架基础(05):事务管理机制,和实现方式
本文源码:GitHub·点这里 || GitEE·点这里 一.Spring事务管理 1.基础描述 Spring事务管理的本质就是封装了数据库对事务支持的操作,使用JDBC的事务管理机制,就是利用jav ...
- AOP面向切面编程的四种实现
一.AOP(面向切面编程)的四种实现分别为最原始的经典AOP.代理工厂bean(ProxyFacteryBean)和默认自动代理DefaultAdvisorAutoProxyCreator以及Bea ...
- Spring AOP 切面编程记录日志和接口执行时间
最近客户现在提出系统访问非常慢,需要优化提升访问速度,在排查了nginx.tomcat内存和服务器负载之后,判断是数据库查询速度慢,进一步排查发现是因为部分视图和表查询特别慢导致了整个系统的响应时间特 ...
- SpringBoot2.0 基础案例(11):配置AOP切面编程,解决日志记录业务
本文源码 GitHub地址:知了一笑 https://github.com/cicadasmile/spring-boot-base 一.AOP切面编程 1.什么是AOP编程 在软件业,AOP为Asp ...
- Spring MVC通过AOP切面编程 来拦截controller 实现日志的写入
首选需要参考的是:[参考]http://www.cnblogs.com/guokai870510826/p/5977948.html http://www.cnblogs.com/guokai8 ...
- Spring框架基础
1 Spring框架 1.1 Spring的基本概念 是一个轻量级的框架,提供基础的开发包,包括消息.web通讯.数据库.大数据.授权.手机应用.session管理 ...
- AOP 切面编程------JoinPoint ---- log日志
AOP 在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是OOP的延续,是软件 ...
- Spring框架基础2
Spring框架基础2 测试Spring的AOP思想和注解的使用 导包(在前面的基础上添加) SpringAOP名词解释 AOP编程思想:横向重复代码,纵向抽取:就是说多个地方重复的代码可以抽取出来公 ...
- Spring框架入门之AOP
Spring框架入门之AOP 一.Spring AOP简单介绍 AOP AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented ...
随机推荐
- [原创] Matlab 指派问题模型代码
指派问题的基本内容 一般来说指派问题解决的是如何将任务分配到人,使得任务完成的效益最大化(成本型效益则求最小值,利润型效益则求最大值).上述问题一个 0 - 1 整数规划问题. 问题围绕着任务和人展开 ...
- Containers vs Serverless:你选择谁,何时选择?
两者都是当今技术时代的热门话题,也都被视为是开发技术的竞争对手. 首先,还有相当多的好奇和担心.此外,两者都是可供工程师使用的.高效的.机器无关的抽象. 但是,在冠军之间,有一个不可逾越的鸿沟.你要么 ...
- Winform组合ComboBox和TreeView实现ComboTree
最近做Winform项目需要用到类似ComboBox的TreeView控件. 虽然各种第三方控件很多,但是存在各种版本不兼容问题.所以自己写了个简单的ComboTreeView控件. 下图是实现效果: ...
- 2018年蓝桥杯java b组第七题
标题:螺旋折线 如图p1.pgn所示的螺旋折线经过平面上所有整点恰好一次. 对于整点(X, Y),我们定义它到原点的距离dis(X, Y)是从原点到(X, Y)的螺旋折线段的长度. 例如dis(0, ...
- 《HelloGitHub》第 42 期
兴趣是最好的老师,HelloGitHub 就是帮你找到兴趣! 简介 分享 GitHub 上有趣.入门级的开源项目. 这是一个面向编程新手.热爱编程.对开源社区感兴趣 人群的月刊,月刊的内容包括:各种编 ...
- spark运行信息及报错问题解决集锦
错误1: ERROR client.RemoteDriver: Failed to start SparkContext: java.lang.IllegalArgumentException: Ex ...
- Python2与Python3的map()
1. map()函数 Python2中,map(func, seq1[,seq2[...[,seqn)将func作用于seq*的每个序列的索引相同的元素,并最终生成一个[func(seq1[0], s ...
- java8 两个时间比较
比如在15:30:30之前: LocalTime.now().isBefore(LocalTime.of(15, 30,30)) 或15:30:30之后 LocalTime.now().isAfter ...
- MongoDB 学习笔记之 检测存储引擎
检测存储引擎: db.serverStatus().storageEngine db.serverStatus().wiredTiger (转)WiredTiger测试结果 单纯写的测试结果 结论:W ...
- mybatis入门百分百
今天重新返回来看自己的mybatis,总结了一些更好入门的办法,下面用最简单的方法带领大家入门. 此处先引入类包的关系图片 1.构建一个==普通==maven项目 构建好之后向pom.xml添加一下依 ...