Spring基础----AOP(1),JDK/CGLIB动态代理

Spring AOP(面向切面编程)

根据个人理解,AOP就是对指定的目标方法绑定各种拦截程序
如:A框架代码是所有程序必须的 , B程序想运行,运行前A框架初始化代码必须先运行 , B程序运行完后还需要执行A框架销毁代码;
如果有100个程序呢 , 那每个程序都需要写入A 框架的初始化和销毁程序 , 这显然不明智
AOP出现就解决了这个问题
如下图所示,
切面: 对目标类进行拦截后运行的程序
目标类的目标方法 : 切入点, 被切面拦截的程序
代理拦截器 : 将所有的切面和目标类引入 (所以的东西代理进来),通过构造器赋值,填充代理方法 ,
最后目标类可以通过代理拦截器产生具有切面拦截的代理对象!!!

在这里插入图片描述


实现代理拦截器

JDK 代理 或者CGLIB代理 动态代理实现代理拦截器
一、原理区别:

java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。

而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。

1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP
2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP

3、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换

4、jdk代理 : 代理对象和目标对象实现了共同的接口
cglib代理 : 代理对象是目标对象的子类

JDK代理 - 实现动态代理拦截器

目标类

public class SalaryMainImp implements SalaryMain {
    @Override
    public void showSalary() {
        System.out.println("查看工资");
    }
}

切面拦截类

//切面
public class Logger {
    public void logger(){
        System.out.println("启动日志~~~~~");
    }
}

***************************************************

//切面
public class Security {
    public void security() {

        System.out.println("启动安全框架~~~~~");
    }
}

代理拦截器

/*  代理拦截器  实现 InvocationHandler
 * 将所有的切面和目标类引入 (所以的东西代理进来)
 * 通过构造器赋值
 * 填充invoke方法
 *
 * */
public class SalaryInterceptor implements InvocationHandler {

    private Object target;  //目标类
    
    private Logger logger;  //日志类切面
    private Security security; //安全框架类切面

    public SalaryInterceptor(Object target, Logger logger, Security security, Privilege privilege) {
        this.target = target;
        this.logger = logger;
        this.security = security;
        this.privilege = privilege;

    }

    @Override
    //整合所需切面和目标类的程序!!!
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        this.logger.logger();     //启动日志
        this.security.security();  //启动安全框架
        
        method.invoke(this.target, args);  //代理目标类的方法
        
        return null;
    }
}

*************************************************************************************
*************************************************************************************

        @Test
        Logger logger = new Logger();   //创建日志对象
        Security security = new Security();     //创建安全框架对象
      
        Object target = new SalaryMainImp(); //目标类

        //创建代理拦截器
        SalaryInterceptor salaryInterceptor = new SalaryInterceptor(target, logger, security);

        //传入目标类装载器,目标类接口,指定拦截器 ,生成代理对象 ,JDK代理只能用目标类接口生产代理对象!所以目标类必须是继承一个接口!
        SalaryMain salaryMain = (SalaryMain) Proxy.newProxyInstance(target.getClass().getClassLoader(),
        
        target.getClass().getInterfaces(), salaryInterceptor);

        salaryMain.showSalary();

总结: 此为JDK动态代理,由于目标类类型为Object ,所以可以传入任何目标类都能生成代理接口


CGLIB代理 - 实现动态代理拦截器

与JDK代理类似,如果切面拦截过多,可以使用集合构造

目标类

public class SalaryMainImp implements SalaryMain {
    @Override
    public void showSalary() {
        System.out.println("查看工资");
    }
}

切面拦截类

//实现 拦截器 切面总接口
public class Logger  implements Interceptor {
    @Override
    public void interceptor() {
        System.out.println("启动日志~~~~~");
    }
}

**********************************************

//实现 拦截器 切面总接口
public class Security implements Interceptor {
    @Override
    public void interceptor() {
        System.out.println("启动安全框架~~~~~");

    }
}

代理拦截器

public class SalaryInterceptor implements MethodInterceptor {

    private Object target;  //目标类
    private List<Interceptor> interceptorList;  //切面集合

    public SalaryInterceptor(Object target, List<Interceptor> interceptorList) {
        this.target = target;
        this.interceptorList = interceptorList;
    }

    /*
     *产生代理对象
     * @return
     * */
    public Object createProxy() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(this.target.getClass());  //设置代理对象的父类
        enhancer.setCallback(this);  //设置拦截器
        return enhancer.create();
    }


    //整合所需切面和目标类
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {

        //遍历切面集合,调用每个切面的拦截方法
        for (Interceptor interceptor : interceptorList) {
            interceptor.interceptor();
        }
        method.invoke(this.target, objects);   //代理目标类的方法

        return null;
    }
}

*************************************************************************
*************************************************************************

@Test

        Logger logger = new Logger();
        Security security = new Security();
        Privilege privilege = new Privilege();
        Object target = new SalaryMainImp(); //目标类

        //将所需切面存入集合中
        List<Interceptor> interceptors = new ArrayList<>();
        interceptors.add(logger);
        interceptors.add(security);
        interceptors.add(privilege);

        //传入 目标类, 切面拦截集合 ,返回代理拦截器
        SalaryInterceptor salaryInterceptor = new SalaryInterceptor(target, interceptors);


        //通过代理拦截器,创建代理对象
        SalaryMainImp salaryMain = (SalaryMainImp) salaryInterceptor.createProxy();

//        Enhancer enhancer=new Enhancer();
//        enhancer.setSuperclass(target.getClass());
//        enhancer.setCallback(salaryInterceptor);
//        SalaryMain salaryMain=(SalaryMain)enhancer.create();  这个步骤可存到代理拦截器中

        salaryMain.showSalary();
        
        /*
        在调用 show () 之前,需要启动某些程序,框架
        这时就可以用该思想,讲切面 和目标类 都进行代理 整合到一起
        * */
    }

总结 : AOP简单来说就是代码的增强, 给指定的程序增加功能!!! ,通过代码拦截器对指定类的方法增加功能!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章