spring-aop源码解析之代理bean的创建以及使用

从前面的简单的分析之中,我们得知,在ioc创建好我们的切入点的bean之后,使用的并不是创建好的bean,而还会为他创建一个代理bean。这个代理bean中有其关于方法增强的属性。具体的代理bean的属性如下图所示。
在这里插入图片描述
可以清楚看到创建的代理对象中有相关的增强器。
再来看看增强器都有什么属性
在这里插入图片描述
增强器的类型 以及属于哪个切面类, 增强器在哪个方法上作用都有相关字段记录。

对于cglib代理来说。他会设置多个callback,同时就必须得有一个callbackFilter来告诉我们代理对象执行方法的时候,用哪一个callback。

在spring-aop中,他为我们设置了7个callback,而执行哪个callback在创建代理对象的时候的filter里面指定了规则。

具体代码在这一块

CglibAopProxy   135  line
//在创建代理对象之前,创建好callback,并且设置好callback的执行规则(也就是callbackFilter)
enhancer.setCallbackFilter(new CglibAopProxy.ProxyCallbackFilter(this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
//设置callback类型 (数组)
enhancer.setCallbackTypes(types);
return this.createProxyClassAndInstance(enhancer, callbacks);

具体的cglib如何创建代理对象以及使用 看我最后的demo就ok
在这里插入图片描述
至于每个callback的作用我们就不做分析了。重点是我们的目标方法执行的话,会触动第一个callback的执行。

所以我来来看看代理对象的创建,以及代理对象的使用

代理对象的创建

AbstractAutoProxyCreator   174  line

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
        if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
            return bean;
        } else if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
            return bean;
            //bean是否有相关切面的注解  没有才会进入到这里
        } else if (!this.isInfrastructureClass(bean.getClass()) && !this.shouldSkip(bean.getClass(), beanName)) {
        	//获取方法增强器 
        	//1、获取所有的增强器
        	//2、获取正处理的类的所有方法
        	//3、遍历,判断有没有方法与增强器匹配,有的话,则收集起来,返回。没有,返回DO_NOT_PROXY
            Object[] specificInterceptors = this.getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, (TargetSource)null);
            if (specificInterceptors != DO_NOT_PROXY) {
            	//需要代理,将beanName先放在map中
                this.advisedBeans.put(cacheKey, Boolean.TRUE);
                //创建代理对象
                Object proxy = this.createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
                //将代理对象也收集在map中
                this.proxyTypes.put(cacheKey, proxy.getClass());
                //返回代理对象。最终ioc里面持有的就是这一块创建的代理对象
                return proxy;
            } else {
            	//不需要代理,直接返回bean
                this.advisedBeans.put(cacheKey, Boolean.FALSE);
                return bean;
            }
        } else {
     
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return bean;
        }
    }

1、判断bean是否需要代理

这一块就不分析代码了,直接看流程图

2、代理对象的创建

这一块就不分析代码了,直接看流程图
在这里插入图片描述
注意! 创建代理对象的时候,如果bean没有实现接口,则使用cglib创建代理对象
如果bean有实现接口,那么就使用jdk创建代理对象

上面我们的流程演示的是使用cglib创建代理对象的过程。

3、代理对象的使用

在这里插入图片描述

4、jdk动态代理与cglib动态代理demo

4.1 jdk动态代理

/**
 * @author 蒙ym
 * @Date 2021/1/27
 */
public class JdkProxy implements InvocationHandler {

    private Object targetClass;

    public JdkProxy(Object targetClass){
    	//设置代理类
        this.targetClass = targetClass;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //执行目标方法
        Object result = method.invoke(targetClass, args);
        return result;
    }


    public Object createProxy(){
    	//创建代理对象   这里是基于接口来创建的
        return Proxy.newProxyInstance(targetClass.getClass().getClassLoader(), targetClass.getClass().getInterfaces(), this);
    }
}

4.2 cglib动态代理

这里需要的jar包括:asm-3.3.1.jar与cglib-2.2.2.jar

**
 * @author 蒙ym
 * @Date 2021/1/27
 */
public class CglibProxy implements MethodInterceptor {

    public Object createProxy(Class<?> clazz){
        Enhancer enhancer = new Enhancer();
        //设置回调函数,也就是代理对象方法执行的类
        enhancer.setCallback(this);
        //设置需要代理的类
        enhancer.setSuperclass(clazz);
        //将构造函数的参数类型放在这里面
        Class[] type = {String.class};
        //将构造函数传的值放在这里面
        Object[] param = {"许嵩"};
        //创建代理对象
        return enhancer.create(type, param);
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
    	//注意!这里需要使用最后一个参数来调invoke。
    	//如果使用第二个参数,那么相当于代理对象再执行一边目标方法,然后再次来到这个intercept方法 最终形成死循环
        Object result = methodProxy.invokeSuper(o, objects);
        return result;
    }
}

测试动态代理

/**
 * @author 蒙ym
 * @Date 2021/1/27
 */
public class MainTest {

    public static void main(String[] args) {
        //测试jdk动态代理
        JdkProxy proxy = new JdkProxy(new XuSong("许嵩"));
        Star star =(Star) proxy.createProxy();
        star.sing();

        //测试cglib动态代理
        CglibProxy cglib = new CglibProxy();
        Star cglibProxy =(Star) cglib.createProxy(XuSong.class);
        cglibProxy.sing();
    }
}

代理接口与代理类

public interface Star {
    /**
     * 给定一个方法
     * @return
     */
    void sing();
}


public class XuSong implements Star {

    private String name;

    public XuSong(String name){
        this.name = name;
    }

    @Override
    public void sing() {
        System.err.println("歌手名字: " + this.name);
    }
}

查看下结果
在这里插入图片描述
再来做一个有多个callback的demo

/**
 * @author 蒙ym
 * @Date 2021/1/28
 * @Desc  callback--one
 */
public class CglibCallBack1 implements MethodInterceptor {

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {

        System.err.println("callBack1的方法执行~~~");
        return methodProxy.invokeSuper(o, objects);
    }
}
/**
 * @author 蒙ym
 * @Date 2021/1/28
 * @Desc  callback--two
 */
public class CglibCallBack2 implements MethodInterceptor {

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.err.println("callBack2的方法执行~~~");
        return methodProxy.invokeSuper(o, objects);
    }
}

callback–one 与 callback–two 一模一样,就是日志打印不一样

再来看看测试类怎么写

/**
 * @author 蒙ym
 * @Date 2021/1/27
 */
public class MainTest {

    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(XuSong.class);
        Class[] clazz = {String.class};
        Object[] param = {"许嵩"};
        //创建callback类型的数组,用来存放我们的callback
        Callback[] callbacks = new Callback[2];
        //依次创建好两个callback
        CglibCallBack1 back1 = new CglibCallBack1();
        CglibCallBack2 back2 = new CglibCallBack2();
        //将callback放入数组中
        callbacks[0] = back1;
        callbacks[1] = back2;
        //设置好callback
        enhancer.setCallbacks(callbacks);
        //设置callback的filter  这个filter决定了最终执行目标方法的时候,会走到哪一个callback中
        enhancer.setCallbackFilter(new CallbackFilter() {
            @Override
            public int accept(Method method) {
            	//打印下都会有哪些方法
                System.out.println("打印方法----》" + method.toString());
                //返回需要执行的callback在callback数组中的下标
                //这个下标所在的callback就是最终执行逻辑的callback
                return 1;
            }
        });
        XuSong proxy =(XuSong) enhancer.create(clazz, param);
        proxy.sing();
    }

看下结果
在这里插入图片描述
至此,aop相关的就结束了,理解的很粗糙,只是大概的流程


版权声明:本文为qq_41001945原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。