Spring基于注解开发的注解使用之AOP(部分源代码分析02)加载过程深刻化【都是基于BeanPostProcessor后置处理器after增强的bean】

目录

 

@EnableAspectJAutoProxy 如何工作的

AnnotationAwareAspectJAutoProxyCreator注册完毕后,如何进行增强的

类图结构

ReflectiveMethodInvocation


@EnableAspectJAutoProxy 如何工作的

/**
 * 1、@EnableAspectJAutoProxy加上这个注解之后,为什么AOP就可以工作了呢?
 * 通过实现这个注解后,然后在注解中
 * @Import(AspectJAutoProxyRegistrar.class)又使用导入的注解,给容器注册这个组件AspectJAutoProxyRegistrar
 * 在配置类启动的时候,会加载ImportBeanDefinitionRegistrar类型的bean,然后通过
 * loadBeanDefinitionsFromRegistrars导入进来
 * 2、然后就执行AspectJAutoProxyRegistrar.registerBeanDefinitions方法
 * 3、然后给容器注册了一个
 * 通过org.springframework.aop.config.AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary方法
 * beanName=org.springframework.aop.config.internalAutoProxyCreator  class=AnnotationAwareAspectJAutoProxyCreator
 * RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
 * beanDefinition.setSource(source);
 * beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
 * Role定义
 *  ROLE_APPLICATION = 0 :用户
 *  ROLE_SUPPORT = 1:某些复杂配置一部分
 *  ROLE_INFRASTRUCTURE = 2:完全内部使用,与用户无关
 * 定义这个bean的应用
 * beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
 * registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
 * 【到此为止,给容器注册这个bean的定义,到时候容器就会通过getBean实例化这个bean】
 * 那AnnotationAwareAspectJAutoProxyCreator类图结构是什么?他主要做的事情是什么?
 *【一般来讲都是利用bean的后置处理器给要创建的bean进行功能增强】
 */

AnnotationAwareAspectJAutoProxyCreator注册完毕后,如何进行增强的

BeanPostProcessor子接口,执行时机在bean创建的前后是不一样的
    --》DestructionAwareBeanPostProcessor bean销毁方法的后置处理器
    --》InstantiationAwareBeanPostProcessor  在bean创建之前,赋值之前
      --》SmartInstantiationAwareBeanPostProcessor 在bean实例化+初始化完成以后
    --》MergedBeanDefinitionPostProcessor Bean构造方法完成实例化,这个允许修改bean的定义
AbstractAutoProxyCreator
@Override//实现了BeanPostProccessor接口的postProcessAfterInitialization方法(这个是在执行后置处理器--初始化完成之后调用)
//AOP的代理在这里实现的
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
    if (bean != null) {
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        if (this.earlyProxyReferences.remove(cacheKey) != bean) {
            return wrapIfNecessary(bean, beanName, cacheKey);
        }
    }
    return bean;
}
AbstractAutoProxyCreator
@Override//实现了InstantiationAwareBeanPostProcessor接口的postProcessBeforeInstantiation方法(拿到bean的定义,允许返回一个代理对象)
    //
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
    Object cacheKey = getCacheKey(beanClass, beanName);

    if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {
        if (this.advisedBeans.containsKey(cacheKey)) {
            return null;
        }
        if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {
            this.advisedBeans.put(cacheKey, Boolean.FALSE);
            return null;
        }
    }

    // Create proxy here if we have a custom TargetSource.
    // Suppresses unnecessary default instantiation of the target bean:
    // The TargetSource will handle target instances in a custom fashion.
    TargetSource targetSource = getCustomTargetSource(beanClass, beanName);
    if (targetSource != null) {
        if (StringUtils.hasLength(beanName)) {
            this.targetSourcedBeans.add(beanName);
        }
        Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource);
        Object proxy = createProxy(beanClass, beanName, specificInterceptors, targetSource);
        this.proxyTypes.put(cacheKey, proxy.getClass());
        return proxy;
    }

    return null;
}

 

类图结构

org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator

增强器

 

ReflectiveMethodInvocation

方法说明

public Object proceed() throws Throwable {
   // We start with an index of -1 and increment early.//第一次是-1
   if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
      return invokeJoinpoint();
   }
   //取第一个动态拦截器:从上面截图可以看见一共有6个(这个仅针对当前分析实例来的--主要切点就这几个)
   Object interceptorOrInterceptionAdvice =
         this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
   //其他代码忽略
    return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}

取第一个:ExposeInvocationInterceptor,然后调用ExposeInvocationInterceptor的invoke方法,把当前类实例this传递进去

      通过ExposeInvocationInterceptor的invoke方法内部,可以看见它其实又调用了ReflectiveMethodInvocation.proceed方法(回去了)

      这个时候,currentInterceptorIndex已经=1了

取第二个:AspectJAroundAdvice,这个是一个环绕通知增强器

      通过AspectJAroundAdvice.的invoke方法

      没得proceed方法,具体执行交给切面类来做

     然后一直等

取第三个:MethodBeforeAdviceInterceptor

     this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());//先执行before
     return mi.proceed();//在返回

取第四个:AspectJAfterAdvice

    这里没执行,直接返回回去了,但是在finally里面里面调用了切面的方法【记录好】

try {
	return mi.proceed();
}
finally {//也就是说当这句话执行的时候,整个调用链就执行完毕【最后一步】
	invokeAdviceMethod(getJoinPointMatch(), null, null);
}

取第五个:AfterReturningAdviceInterceptor

    返回,等上面执行完了,在执行afterReturning

    this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis())

取第六个:AspectJAfterThrowingAdvic

try {
	return mi.proceed();//返回
}
catch (Throwable ex) {//如果上面执行有异常的时候,在补货异常
	if (shouldInvokeOnThrowing(ex)) {
		invokeAdviceMethod(getJoinPointMatch(), null, ex);//执行异常的方法
	}
	throw ex;//抛出异常
}

     

 

  • ExposeInvocationInterceptor的invoke方法

  • AspectJAroundAdvice 切面环绕

Method名称.invoke(对象实例,参数);

上面的aspectJAdviceMthod调用了下面截图的环绕方法

在然后通过point.proceed

  • MethodBeforeAdviceInterceptor

advice.before

调用抽象类提供的统一方法【原理还是mehtod.invoke反射调用】

一调用又到切面的方法

  • AspectJAfterAdvice

  • AfterReturningAdviceInterceptor

  • AspectJAfterThrowingAdvice

  • invokeJoinpoint()

参数上面的args


模拟实现切面效果


package wolf.almm.sty.spring;

import lombok.AllArgsConstructor;
import lombok.Data;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * 模拟实现切面通知
 */
public class Simple {
    public static void main(String[] args) throws Throwable {
        ReflectiveMethodInvocation reflectiveMethodInvocation = new ReflectiveMethodInvocation();
        reflectiveMethodInvocation.proceed();
        /**
         *开始执行环绕通知
         *before开始执行
         * WolfService-getWolfMsg-be call
         *afterReturning返回结果:Wolf(name=朗阿拉, age=打死不出门)
         *AspectJAfterAdvice--执行
         *after
         *---然后等我上面的执行完了多
         *环绕通知执行完毕
         */
    }

}

class ReflectiveMethodInvocation implements MethodHandler {
    private int currentInterceptorIndex = -1;
    final static List interceptorsAndDynamicMethodMatchers = new ArrayList();
    private Method method = WolfService.class.getMethod("getWolfMsg", String.class, String.class);
    private Object target = new WolfService();
    protected Object[] args = new Object[]{"朗阿拉", "打死不出门"};

    static {
        /**
         * 执行流程
         * 1、环绕通知
         * 2、before通知
         * 3、after通知
         * 4、afterReturning通知
         * 5、如果有异常就是异常通知
         */
        interceptorsAndDynamicMethodMatchers.add(new ExposeInvocationInterceptor());
        interceptorsAndDynamicMethodMatchers.add(new AspectJAroundAdvice());
        interceptorsAndDynamicMethodMatchers.add(new MethodBeforeAdviceInterceptor());
        interceptorsAndDynamicMethodMatchers.add(new AspectJAfterAdvice());
        interceptorsAndDynamicMethodMatchers.add(new AfterReturningAdviceInterceptor());
        interceptorsAndDynamicMethodMatchers.add(new AspectJAfterThrowingAdvice());
    }

    ReflectiveMethodInvocation() throws NoSuchMethodException {
    }

    public Object proceed() throws Throwable {
        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            return invokeJoinpoint();
        }

        ClassI interceptorOrInterceptionAdvice =
                (ClassI) this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);

        return interceptorOrInterceptionAdvice.invoke(this);
    }

    Object invokeJoinpoint() throws Throwable {
        return method.invoke(target, args);
    }
}

interface MethodHandler {
    Object proceed() throws Throwable;
}

interface ClassI {
    Object invoke(MethodHandler invocation) throws Throwable;
}

//默认的
class ExposeInvocationInterceptor implements ClassI {
    @Override
    public Object invoke(MethodHandler invocation) throws Throwable {
        return invocation.proceed();
    }
}

//默认的
class AspectJAroundAdvice implements ClassI {
    @Override
    public Object invoke(MethodHandler invocation) throws Throwable {
        /**
         * 执行环绕通知方法
         * 1、先执行目标方法,然后把MethodHandler提供进去
         */
        return PointCut.class.getMethod("aroundMethod", MethodHandler.class).invoke(new PointCut(), invocation);
    }
}

class MethodBeforeAdviceInterceptor implements ClassI {
    @Override
    public Object invoke(MethodHandler invocation) throws Throwable {
        PointCut.class.getMethod("before").invoke(new PointCut());
        return invocation.proceed();
    }
}

class AspectJAfterAdvice implements ClassI {
    @Override
    public Object invoke(MethodHandler invocation) throws Throwable {
        try {
            return invocation.proceed();
        } finally {
            System.out.println("AspectJAfterAdvice--执行");
            PointCut.class.getMethod("after").invoke(new PointCut());
        }
    }
}

class AfterReturningAdviceInterceptor implements ClassI {
    @Override
    public Object invoke(MethodHandler invocation) throws Throwable {
        Object retVal = invocation.proceed();
        PointCut.class.getMethod("afterReturning", Object.class).invoke(new PointCut(), retVal);
        return retVal;
    }
}

class AspectJAfterThrowingAdvice implements ClassI {
    @Override
    public Object invoke(MethodHandler invocation) throws Throwable {
        try {
            return invocation.proceed();
        } catch (Exception ex) {
            PointCut.class.getMethod("afterThrowing").invoke(new PointCut(), ex);
            throw ex;
        }
    }
}

class PointCut {

    public void aroundMethod(MethodHandler invocation) throws Throwable {
        System.out.println("开始执行环绕通知");
        invocation.proceed();//继续执行业务方法
        System.out.println("---然后等我上面的执行完了多");
        System.out.println("环绕通知执行完毕");
    }

    public void before() {
        System.out.println("before开始执行");
    }

    public void after() {
        System.out.println("after");
    }

    public void afterReturning(Object result) {
        System.out.println("afterReturning" + "返回结果:" + result);
    }

    public void afterThrowing(Exception exception) {
        System.out.println("LogAspectJUtil-LogAspectJUtil-LogAspect--AfterThrowing" + exception.getMessage());
    }

}


@Data
@AllArgsConstructor
class Wolf {
    private String name;

    private String age;

}

class WolfService {//implements IWolfService {

    public Wolf getWolfMsg(String wolfName, String wolfAge) {
        System.out.println("WolfService-getWolfMsg-be call");
        return new Wolf(wolfName, wolfAge);
    }
}

JDK基于接口代理和cglib基于实现代理,都是一样的。

  • JDK动态代理
关键点
1、实现InvocationHandler接口
--实现接口的invoke方法
--注意:invoke里面的method.invoke(target, args) target目标(需要提供--具体接口实例)
2、代理对象创建方式
--newProxyInstance第一个参数,提供一个类加载器(供JVM可以加载类到虚拟机中)
--newProxyInstance第二个参数,目标实现的接口(可以多个)
--newProxyInstance第三个参数,实现了InvocationHandler接口的动态代理对象
Proxy.newProxyInstance(target.getClass()
                .getClassLoader(), target.getClass().getInterfaces(), this)

public class JDKDynamicProxy implements InvocationHandler {

    private Object target;

    public JDKDynamicProxy(Object target) {
        this.target = target;
    }

    /**
     * 获取被代理接口实例对象
     *
     * @param <T>
     * @return
     */
    public <T> T getProxy() {
        return (T) Proxy.newProxyInstance(target.getClass()
                .getClassLoader(), target.getClass().getInterfaces(), this);
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Do something before");
        Object result = method.invoke(target, args);
        System.out.println("Do something after");
        return result;
    }
}

public interface Subject {
    void doSomething();
}

public class RealSubject implements Subject {
    @Override
    public void doSomething() {
        System.out.println("RealSubject do something");
    }
}



public class ClientTest {

    public static void main(String[] args) {
        // jdk动态代理测试
        //Subject subject = new JDKDynamicProxy(new RealSubject()).getProxy();
        //subject.doSomething();
        //Subject subject2 = new JDKDynamicProxy(subject).getProxy();
        //subject2.doSomething();
        Subject subject3 = new JDKDynamicProxy(new RealSubject()).getProxy();
        subject3.doSomething();

        //尝试直接类使用动态代理
        //RealSubject2 subject2 = new JDKDynamicProxy(new RealSubject2()).getProxy();
        //subject2.doSomething();
    }
}
  • cglib

转自::https://blog.csdn.net/difffate/article/details/70552056 

尊重原创

前面介绍了代理模式,讲了动态代理常见的实现方式,包含了JDK的动态代理和CGLib的动态代理。本文将介绍下CGLib动态代理及几种用法。CGLib(Code Generation Library)是一个高效的代码生成库,底层实现是使用asm来转换字节码生成类。在生成代理类的场景中,由于JDK动态代理必须要求源对象有实现接口,而实际场景中,并不是所有类都有实现接口,因此使用CGLib可以用在未实现接口的类上。

值得注意的几点是:

1)使用CGLib代理的类不能是final修饰的,因为代理类需要继承主题类;

2)final修饰的方法不会被切入;

3)如果主题类的构造函数不是默认空参数的,那么在使用Enhancer类create的时候,选择create(java.lang.Class[] argumentTypes, java.lang.Object[] arguments) 方法。

接下来认识实现动态代理最重要的一个接口 MethodInteceptor


package net.sf.cglib.proxy;
 
/**
 * General-purpose {@link Enhancer} callback which provides for "around advice".
 * @author Juozas Baliuka <a href="mailto:baliuka@mwm.lt">baliuka@mwm.lt</a>
 * @version $Id: MethodInterceptor.java,v 1.8 2004/06/24 21:15:20 herbyderby Exp $
 */
public interface MethodInterceptor
extends Callback
{
    /**
     * All generated proxied methods call this method instead of the original method.
     * The original method may either be invoked by normal reflection using the Method object,
     * or by using the MethodProxy (faster).
     * @param obj "this", the enhanced object
     * @param method intercepted Method
     * @param args argument array; primitive types are wrapped
     * @param proxy used to invoke super (non-intercepted method); may be called
     * as many times as needed
     * @throws Throwable any exception may be thrown; if so, super method will not be invoked
     * @return any value compatible with the signature of the proxied method. Method returning void will ignore this value.
     * @see MethodProxy
     */    
    public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args,
                               MethodProxy proxy) throws Throwable;
 
}

MethodInterceptor,从名字上方法拦截器,就是对方法做切入的。intercept方式的4个参数分别对应增强对象、调用方法、方法参数以及调用父类方法的代理。使用MethodProxy速度会更快,所以后面将用


下面介绍几种用法,这里使用spring包中cglib,其实和引单独的cglib包是一样,只不过spring为了版本不冲突,将cglib包含在自己的包中。

先定义一个主题对象


/**
 * Create by zxb on 2017/4/23
 */
public class DBQuery {
 
    public DBQuery() {
    }
 
    public DBQuery(Integer i) {
        System.out.println("Here's in DBQuery Constructor");
    }
 
    public String getElement(String id) {
        return id + "_CGLib";
    }
 
    public List<String> getAllElements() {
        return Arrays.asList("Hello_CGLib1", "Hello_CGLib2");
    }
 
    public String methodForNoop() {
        return "Hello_Noop";
    }
 
    public String methodForFixedValue(String param) {
        return "Hello_" + param;
    }
 
    public final String sayHello() {
        return "Hello Everyone!";
    }
}

(一)单回调
切入类:


/**
 * Create by zxb on 2017/4/22
 */
public class DBQueryProxy implements MethodInterceptor {
 
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("Here in interceptor !");
        return methodProxy.invokeSuper(o, objects);
    }
}

测试类:


public class TestCGLibProxy {
 
    public static void main(String[] args) {
        DBQueryProxy dbQueryProxy = new DBQueryProxy();
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(DBQuery.class);
        enhancer.setCallback(dbQueryProxy);
//        DBQuery dbQuery = (DBQuery)enhancer.create(new Class[]{Integer.class}, new Object[]{1});
        DBQuery dbQuery = (DBQuery) enhancer.create();
        System.out.println(dbQuery.getElement("Hello"));
        System.out.println();
        System.out.println(dbQuery.getAllElements());
        System.out.println();
        System.out.println(dbQuery.sayHello());
    }
}

执行结果:


(二)多回调

在前面的基础上,加个切入类,并通过CallbackFilter来决定是使用哪个切入类


/**
 * Create by zxb on 2017/4/22
 */
public class DBQueryProxy2 implements MethodInterceptor {
 
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("Here in interceptor 2!");
        return methodProxy.invokeSuper(o, objects);
    }
}

测试类:


/**
 * Create by zxb on 2017/4/22
 */
public class TestCGLibProxy {
 
    public static void main(String[] args) {
        DBQueryProxy dbQueryProxy = new DBQueryProxy();
        DBQueryProxy2 dbQueryProxy2 = new DBQueryProxy2();
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(DBQuery.class);
        enhancer.setCallbacks(new Callback[]{dbQueryProxy, dbQueryProxy2});
        enhancer.setCallbackFilter(new CallbackFilter() {
 
            public int accept(Method method) {
                if (method.getName().equals("getElement")) {
                    return 0;
                } else {
                    return 1;
                }
            }
        });
        DBQuery dbQuery = (DBQuery) enhancer.create();
        System.out.println("========Inteceptor By DBQueryProxy ========");
        System.out.println(dbQuery.getElement("Hello"));
        System.out.println();
        System.out.println("========Inteceptor By DBQueryProxy2 ========");
        System.out.println(dbQuery.getAllElements());
    }
}

执行结果:


(三)不处理

利用枚举常量 Callback noopCb = NoOp.INSTANCE;

测试类:


public class TestCGLibProxy {
 
    public static void main(String[] args) {
        DBQueryProxy dbQueryProxy = new DBQueryProxy();
        DBQueryProxy2 dbQueryProxy2 = new DBQueryProxy2();
        Callback noopCb = NoOp.INSTANCE;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(DBQuery.class);
        enhancer.setCallbacks(new Callback[]{dbQueryProxy, dbQueryProxy2, noopCb});
        enhancer.setCallbackFilter(new CallbackFilter() {
 
            public int accept(Method method) {
                if (method.getName().equals("getElement")) {
                    return 0;
                } else if (method.getName().equals("getAllElements")) {
                    return 1;
                } else {
                    return 2;
                }
            }
        });
        DBQuery dbQuery = (DBQuery) enhancer.create();
        System.out.println("========Inteceptor By DBQueryProxy ========");
        System.out.println(dbQuery.getElement("Hello"));
        System.out.println();
        System.out.println("========Inteceptor By DBQueryProxy2 ========");
        System.out.println(dbQuery.getAllElements());
        System.out.println();
        System.out.println("========Return Original Value========");
        System.out.println(dbQuery.methodForNoop());
    }
}

执行结果:


(四)固定值

需要实现FixedValue接口,会忽略原来函数的返回值,使用固定值来替换。


/**
 * 返回固定的值
 * Create by zxb on 2017/4/23
 */
public class DBQueryProxyFixedValue implements FixedValue {
 
    public Object loadObject() throws Exception {
        System.out.println("Here in DBQueryProxyFixedValue ! ");
        return "Fixed Value";
    }
}

测试类:


public class TestCGLibProxy {
 
    public static void main(String[] args) {
        DBQueryProxy dbQueryProxy = new DBQueryProxy();
        DBQueryProxy2 dbQueryProxy2 = new DBQueryProxy2();
        Callback noopCb = NoOp.INSTANCE;
        Callback fixedValue = new DBQueryProxyFixedValue();
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(DBQuery.class);
        enhancer.setCallbacks(new Callback[]{dbQueryProxy, dbQueryProxy2, noopCb, fixedValue});
        enhancer.setCallbackFilter(new CallbackFilter() {
 
            public int accept(Method method) {
                if (method.getName().equals("getElement")) {
                    return 0;
                } else if (method.getName().equals("getAllElements")) {
                    return 1;
                } else if (method.getName().equals("methodForNoop")) {
                    return 2;
                } else if (method.getName().equals("methodForFixedValue")) {
                    return 3;
                } else {
                    return 0;
                }
            }
        });
        DBQuery dbQuery = (DBQuery) enhancer.create();
        System.out.println("========Inteceptor By DBQueryProxy ========");
        System.out.println(dbQuery.getElement("Hello"));
        System.out.println();
        System.out.println("========Inteceptor By DBQueryProxy2 ========");
        System.out.println(dbQuery.getAllElements());
        System.out.println();
        System.out.println("========Return Original Value========");
        System.out.println(dbQuery.methodForNoop());
        System.out.println();
        System.out.println("========Return Fixed Value========");
        System.out.println(dbQuery.methodForFixedValue("myvalue"));
    }
}

执行结果:

(五)懒加载

CGLib的懒加载,可以用在一些不需要立即加载完整对象实例的场景,比如说Hibernate中的查询对象,如果这个对象有关联其他对象,这个时候不会马上将关联对象一起查询出来关联,要等到调用到这个关联对象时才去做查询。利用CGLib的懒加载机制,可以很好的实现这个需求。需要了解2个接口,LazyLoader和Dispatcher。这两个接口的定义如下:


public interface LazyLoader extends Callback {
    Object loadObject() throws Exception;
}
 
public interface Dispatcher extends Callback {
    Object loadObject() throws Exception;
}

它们都继承了Callback接口,都有一个loadObject的方法,区别在于LazyLoader只有在第一次调用时,会执行loadObject获取对象,而Dispatcher会在每次调用时都触发loadObject方法,不理解?没关系,后面代码示例上可以看到明显的区别。假定有个学生类(Student),学术类包含2门课的课程表对象,分别是英语课程表(EnglishSchedule)和数学课程表(MathSchedule),它们都是课程表类的实例

/**
 * 课程表
 * Create by zxb on 2017/4/23
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Schedule {
 
    private String courseName;
 
    private Date courseTime;
}

EnglishSchedule属性的加载依赖于ScheduleLazyLoader


/**
 * Create by zxb on 2017/4/23
 */
public class ScheduleLazyLoader implements LazyLoader {
 
    public Object loadObject() throws Exception {
        System.out.println("before LazyLoader init...you can query from db...");
        Schedule schedule = new Schedule();
        schedule.setCourseName("English");
        Calendar calendar = Calendar.getInstance();
        calendar.set(2017,3,28);
        schedule.setCourseTime(calendar.getTime());
        System.out.println("after LazyLoader init...");
        return schedule;
    }
}

MathSchedule属性的加载依赖于ScheduleDispatcher

/**
 * Create by zxb on 2017/4/23
 */
public class ScheduleDispatcher implements Dispatcher {
 
    public Object loadObject() throws Exception {
        System.out.println("before Dispatcher init...you can query from db...");
        Schedule schedule = new Schedule();
        schedule.setCourseName("Math");
        Calendar calendar = Calendar.getInstance();
        calendar.set(2017,4,1);
        schedule.setCourseTime(calendar.getTime());
        System.out.println("after Dispatcher init...");
        return schedule;
    }
}

学生类:
定义时,需要对EnglishSchedule和MathSchedule先初始为动态代理的对象


package org.zheng.proxy.cglib.lazyload;
 
import lombok.Data;
import org.springframework.cglib.proxy.Enhancer;
 
/**
 * Create by zxb on 2017/4/23
 */
@Data
public class Student {
 
    private int id;
 
    private String name;
 
    /**
     * 英语课时间表
     */
    private Schedule EnglishSchedule;
 
    /**
     * 数学课时间表
     */
    private Schedule MathSchedule;
 
    public Student(int id, String name) {
        this.id = id;
        this.name = name;
        this.EnglishSchedule = createEnglishSchedule();
        this.MathSchedule = createMathSchedule();
    }
 
    private Schedule createEnglishSchedule() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Schedule.class);
        enhancer.setCallback(new ScheduleLazyLoader());
        return (Schedule) enhancer.create();
    }
 
    private Schedule createMathSchedule() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Schedule.class);
        enhancer.setCallback(new ScheduleDispatcher());
        return (Schedule) enhancer.create();
    }
}

测试类:

/**
 * 延迟加载属性
 * Create by zxb on 2017/4/23
 */
public class LazyLoadTest {
 
    public static void main(String[] args) {
        Student student = new Student(666, "XiaoMing");
        System.out.println("id=" + student.getId());
        System.out.println("name=" + student.getName());
        // LazyLoader 只有第一次,Dispatcher是每次都会进loadObject的方法
        System.out.println("========First Get  EnglishSchedule ========");
        System.out.println(student.getEnglishSchedule());
        System.out.println();
        System.out.println("========First Get  MathSchedule ========");
        System.out.println(student.getMathSchedule());
        System.out.println();
        System.out.println("========Second Get  EnglishSchedule ========");
        System.out.println(student.getEnglishSchedule());
        System.out.println();
        System.out.println("========Second Get  MathSchedule ========");
        System.out.println(student.getMathSchedule());
    }
}

执行结果:


可以看到第二次取懒加载对象的时候,实现LoadLazy接口不会重新执行loadObject,而实现Dispatcher的会重新执行LoadObject方法:)

以上,就是使用CGLib的几种常见用法。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值