AOP用于处理系统中分布于各个模块的横切关注点,比如事务管理、日志、缓存等。
AOP实现的关键,在于AOP框架自动创建的AOP代理,AOP代理主要分为静态代理和动态代理,静态代理的代表为AspectJ;而动态代理则以Spring AOP为代表。
静态代理 AspectJ
AspectJ是什么?
Eclipse AspectJ is a seamless aspect-oriented extension to the Java™ programming language. It is Java platform compatible easy to learn and use.
AspectJ是Java的扩展,用于实现面向切面编程。
AspectJ有自己的编辑器ajc,
AspectJ 官网
Eclipse AspectJprojects.eclipse.orgAspectJ 入门www.jianshu.com使用AspectJ的编译时增强,实现AOP。
之前提到,AspectJ是静态代理的增强。所谓的静态代理,就是AOP框架会在编译阶段生成AOP代理类,因此也称为编译时增强。
它会在编译阶段将Aspect织入Java字节码中,运行的时候就是经过增强之后的AOP对象。proceed方法就是回调执行被代理类中的方法。
动态代理(Spring AOP)
Spring AOP官方文档
Core Technologiesdocs.spring.io1.与AspectJ的静态代理不同,Spring AOP使用的是动态代理。所谓的动态代理,就是说AOP框架不会去修改字节码,而是在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。
2.Spring AOP中的动态代理,主要有两种方式:JDK动态代理和CGLIB动态代理。
JDK动态代理通过“反射”来接收被代理的类,并且要求被代理的类必须实现一个接口。JDK动态代理的核心是InvocationHandler接口和Proxy类。如果目标类没有实现接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。
3.CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态地生成某个类的子类。注意,CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。
使用动态代理实质上就是调用时拦截对象方法,对方法进行改造、增强!
测试CGlib生成的动态代理
测试类
package com.example.demo.aop;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@SpringBootApplication
@RestController
//@EnableAspectJAutoProxy
public class SpringBootDemoApplication {// 直接用Chinese类注入@Autowiredprivate Landlord landlord;@RequestMapping("/test")public void test() {landlord.service();System.out.println(landlord.getClass());}public static void main(String[] args) {SpringApplication.run(SpringBootDemoApplication.class, args);}
}
Landlord类
package com.example.demo.aop;import org.springframework.stereotype.Component;@Component("landlord")
public class Landlord {public void service() {// 仅仅只是实现了核心的业务功能System.out.println("签合同");System.out.println("收房租");}
}
Broker类
package com.example.demo.aop.aspect;import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;@Component
@Aspect
class Broker {@Before("execution(* com.example.demo.aop.Landlord.service())")public void before() {System.out.println("带租客看房");System.out.println("谈价格");}@After("execution(* com.example.demo.aop.Landlord.service())")public void after() {System.out.println("交钥匙");}
}
运行结果
带租客看房
谈价格
签合同
收房租
交钥匙
class com.example.demo.aop.Landlord$$EnhancerBySpringCGLIB$$1f1c504a