Spring学习05-[AOP学习-AOP原理和事务]

发布于:2024-07-08 ⋅ 阅读:(54) ⋅ 点赞:(0)

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动态代理会继承一个目标类的代理类
    在这里插入图片描述

事务


网站公告

今日签到

点亮在社区的每一天
去签到