AOP核心概念:
切面(aspect):类是对物体特征的抽象,切面就是对横切关注点的抽象 横切关注点:对哪些方法进行拦截,拦截后怎么处理,这些关注点称之为横切关注点。 连接点(joinpoint):被拦截到的点,Spring 只支持方法类型的连接点,连接点指的是被拦截到的方法,连接点还可以是字段或者构造器。 切入点(pointcut):对连接点进行拦截的定义 通知(advice):所谓通知指的就是指拦截到连接点之后要执行的代码,通知分为前置、后置、异常、最终、环绕通知五类。 目标对象:代理的目标对象 织入(weave):将切面应用到目标对象并导致代理对象创建的过程 引入(introduction):在不修改代码的前提下,引入可以在运行期为类动态地添加一些方法或字段。
AOP 主要应用场景有:
Authentication 权限
Caching 缓存
Context passing 内容传递
Error handling 错误处理
Lazy loading 懒加载
Debugging 调试
logging, tracing, profiling and monitoring 记录跟踪 优化 校准
Performance optimization 性能优化
Persistence 持久化
Resource pooling 资源池
Synchronization 同步
Transactions 事务
AOP 两种代理方式:
Spring 提供了两种方式来生成代理对象: JDKProxy 和 Cglib,具体使用哪种方式生成由AopProxyFactory 根据 AdvisedSupport 对象的配置来决定。默认的策略是如果目标类是接口,则使用 JDK 动态代理技术,否则使用 Cglib 来生成代理。
JDK 动态接口代理
JDK 动态代理主要涉及到 java.lang.reflect 包中的两个类:Proxy 和 InvocationHandler。InvocationHandler是一个接口,通过实现该接口定义横切逻辑,并通过反射机制调用目标类的代码,动态将横切逻辑和业务逻辑编制在一起。Proxy 利用 InvocationHandler 动态创建一个符合某一接口的实例,生成目标类的代理对象。
CGLib 动态代理
CGLib 全称为 Code Generation Library,是一个强大的高性能,高质量的代码生成类库,可以在运行期扩展 Java 类与实现 Java 接口,CGLib 封装了 asm,可以再运行期动态生成新的 class。
和 JDK 动态代理相比较:JDK 创建代理有一个限制,就是只能为接口创建代理实例,而对于没有通过接口定义业务方法的类,则可以通过 CGLib 创建动态代理。
AOP简单使用:
@Component @Aspect public class AspectText { /* aop的重点概念: Pointcut(切入点):被增强的方法 Advice(通知/ 增强):封装增强业务逻辑的方法 Aspect(切面):切点+通知 Weaving(织入):将切点与通知结合的过程 前置通知 <aop:before> 用于配置前置通知。指定增强的方法在切入点方法之前执行 后置通知 <aop:after-returning> 用于配置后置通知。指定增强的方法在切入点方法之后执行 环绕通知 <aop:around> 用于配置环绕通知。指定增强的方法在切入点方法之前和之后都执行 异常抛出通知 <aop:throwing> 用于配置异常抛出通知。指定增强的方法在出现异常时执行 最终通知 <aop:after> 用于配置最终通知。无论增强方式执行是否有异常都会执行 * */ @Before("execution(* com.sandwich.controller.admin.*(..))") public void before(){ System.out.println("before增强方法"); } @Around("pointcut()") public Object around(ProceedingJoinPoint pjp) throws Throwable { System.out.println("around增强前"); Object proceed = pjp.proceed(); System.out.println("around增强后"); return proceed; } @AfterReturning("pointcut()") public void afterReturning(){ System.out.println("afterReturning返回后"); } //设置切点表达式:可以共用 @Pointcut("execution(* com.sandwich.controller.admin.*(..))") public void pointcut(){ } }