AOP原理和事务
- AOP
- AOP底层原理
- 比如下面的代码案例手动模拟AOP
- 动态代理详解
- JDK动态代理
- 具体实现
- Cglib动态代理
- 具体实现
- jdk动态代理和cglib动态代理的区别
- 事务
AOP
AOP底层原理
当实现了AOP,Spring会根据当前的bean创建动态代理(运行时生成一个代理类)
面试题:为什么执行方法的时候,会执行切面里的通知方法?
比如下面的代码案例手动模拟AOP
- 模拟切面类
@Component
public class LogAspect {
public void logBefore() {
System.out.println("aop前置通知");
}
public void logAfter(){
System.out.println("aop后置通知");
}
public void logReturn(){
System.out.println("aop返回通知");
}
public void logThrowting(){
System.out.println("aop异常通知");
}
}
- 动态代理类
@Component
public class ProxyUserService extends UserService {
@Autowired
private LogAspect logAspect;
@Override
public String add() throws InterruptedException {
String result = null;
try {
//调用切面类-前置通知
logAspect.logBefore();
//调用目标方法
result = super.add();
//调用切面类返回通知
logAspect.logReturn();
} catch (Exception e) {
//调用切面类-异常通知
logAspect.logThrowting();
e.printStackTrace();
} finally {
//调用切面类-后置通知
logAspect.logAfter();
}
return result;
}
}
为什么断点可以进入切面类中的通知方法中?
从上述代码中可以看到,在AOP动态代理中,在Spring代理类中,帮我们调用了切面中的前置通知,后置通知、返回通知、异常通知这些通知方法,所以断点可以进入。
动态代理详解
- jdk动态代理
- cglib动态代理
JDK动态代理
JDK动态代理是基于接口的,生成出来的代理类实现了类接口
- 核心代码
第一个参数:类加载器
第二个参数:需要代理的接口
第三个参数:InvocationHandler(调用程序处理器,必须重写invoke方法)
Proxy.newProxyInstance(TestJdkProxy.class.getClassLoader(),
UserService.class.getInterfaces(),
new MyHandler(new UserService())
);
具体实现
- 接口
public interface IUserService {
void add();
}
- 实现类
public class UserService implements IUserService{
@Override
public void add() {
System.out.println("添加用户");
}
}
- 自定义一个InvocationHandler(目的是优化代码降低耦合,提高代码维护性)
public class MyHandler implements InvocationHandler {
Object target;
public MyHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("执行前置通知");
//执行目标方法
Object returnValue = method.invoke(target, args);
System.out.println("执行后置通知");
return returnValue;
}
}
- 测试
生成出来的代理类instance 实现了IUserService 接口
@Component
public class TestJdkProxy{
public void test(){
IUserService instance = (IUserService) Proxy.newProxyInstance(TestJdkProxy.class.getClassLoader(),
UserService.class.getInterfaces(),
new MyHandler(new UserService())
);
//生成出来的代理类instance 实现了IUserService 接口
instance.add();
}
}
Cglib动态代理
用JDK动态代理实现有一个缺点,必须实现接口,Cglib就回避了这个问题,因为cglib实现机制是基于子父类的
cglib动态代理不同于jdk动态代理。cglib动态代理需要依赖于第三方jar包,但是被spring进行了整合,所以不用特意的去引jar包
- 核心代码
Enhancer enhancer = new Enhancer();
//设置被代理的类
enhancer.setSuperclass(PersonService.class);
//设置处理类
enhancer.setCallback(new MyCallback(new PersonService()));
//生成基于cglib动态代理的 代理类,不同于jdk动态代理它是继承自PersonService
PersonService personService = (PersonService) enhancer.create();
personService.add();
具体实现
- 需要代理的类
public class PersonService {
public void add(){
System.out.println("添加人口");
}
}
- 自定义mycallback,需要实现MethodInterceptor接口
public class MyCallback implements MethodInterceptor {
Object object;
public MyCallback(Object object) {
this.object = object;
}
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("执行前置通知");
//执行目标方法
Object returnValue = method.invoke(object, args);
System.out.println("执行后置通知");
return returnValue;
}
}
- 测试
生成基于cglib动态代理的 代理类,不同于jdk动态代理它是继承自PersonService
public void test(){
Enhancer enhancer = new Enhancer();
//设置被代理的类
enhancer.setSuperclass(PersonService.class);
//设置处理类
enhancer.setCallback(new MyCallback(new PersonService()));
//生成基于cglib动态代理的 代理类,不同于jdk动态代理它是继承自PersonService
PersonService personService = (PersonService) enhancer.create();
personService.add();
}
jdk动态代理和cglib动态代理的区别
jdk动态代理是基于接口的,只能代理实现了接口的类。cglib动态代理基于继承的,可以代理未实现接口的类
- jdk动态代理会生成一个实现了接口的代理类
- cglib动态代理会继承一个目标类的代理类