• Spring动态代理源码分析


            说到Spring的核心功能,Spring AOP是始终绕不过去的一个点。而说到Spring AOP,开发中我们经常会用到这个功能,比如:日志记录、权限校验、事务管理等。我们也大概知道它基于动态代理实现的,那除了Spring AOP,Spring还有哪些地方使用到了动态代理?Spring中的动态代理又是如何实现的?让我们跟着这篇文章来一探究竟。

    一、代理模式

            代理模式是23中设计模式中比较常见的一种设计模式。代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。说简单点,代理模式就是设置一个中间代理来控制访问原目标对象,以达到增强原对象的功能和简化访问方式。通俗地来讲代理模式就是我们生活中常见的中介。

            Java中一般使用代理在不改变目标类的基础,对类做增强处理。其实代理可以改变目标类,但是我们一般都不会去这样做,算是一种约定俗成的做法。

            那我们就先来说说代理模式。代理模式分为静态代理和动态代理。

    (1)静态代理

     (i)静态代理的实现

    • 继承
    • 继承+聚合

            静态代理的应用场景:进行代码升级,例如,在原来的功能模块上添加新的功能,我们可以不用修改原来的底层代码,只需要通过代理模式来进行代码迭代。

            例如:系统原来只是简单的实现了登录功能。

    1. public class Service {
    2.    public void login(){
    3.        System.out.println("doLogin……");
    4.   }
    5. }

            第一次更新后,加入了权限校验模块。

    1. public class CheckService extends Service{
    2.    private Service target;
    3.    public CheckService(Service target) {
    4.        this.target = target;
    5.   }
    6.    @Override
    7.    public void login() {
    8.        System.out.println("authentication……");
    9.        target.login();
    10.   }
    11. }

            第二次更新,增加了日志模块。

    1. public class LogService extends Service{
    2.    private Service target;
    3.    public LogService(Service service) {
    4.        this.target = service;
    5.   }
    6.    @Override
    7.    public void login() {
    8.        System.out.println("print Logging……");
    9.        target.login();
    10.   }
    11. }

            系统更新后,只需要修改很少的主体代码就可以实现代码升级。

    1. public static void main(String[] args) {
    2.        Service service = new Service();
    3. // 第一次更新
    4.        Service checkService = new CheckService(service);
    5.        checkService.login();
    6. // 第二次更新​
    7.        Service loginService = new LogService(checkService);
    8.        loginService.login();
    9.   }

            但更多的时候是,第二次更新时,第一次更新的就被舍弃了,随着系统的迭代,舍弃的代码会越来越多。

            上面的代码可能表达的比较隐晦,我们使用下面的方式实现静态代理多一些。

    1. public interface IService {
    2. void process();
    3. }
    4. //实际处理类
    5. public class TargetService implements IService {
    6. public void process(){
    7. System.out.println("TargetService ……");
    8. }
    9. }
    10. public class ProxyService implements IService {
    11. private IService target;
    12. public ProxyService(IService target){
    13. this.target = target;
    14. }
    15. public void process(){
    16. System.out.println("before Proxy doing ……");
    17. target.process();
    18. System.out.println("after Proxy doing ……");
    19. }
    20. }
    21. main(){
    22. TargetService target = new TargetService();
    23. ProxyService proxy = new ProxyService(target);
    24. proxy.process();
    25. }

    (ii)静态代理的优缺点

            优点:可以在不修改目标对象的前提下扩展目标对象的功能。

            缺点:如果需要代理多个类,每个类都会有一个代理类,会导致代理类无限制扩展;如果类中有多个方法,同样的代理逻辑需要反复实现、应用到每个方法上,一旦接口或基类增加方法,目标对象与代理对象都要进行修改。

    (2)动态代理

            (i)JDK动态代理

            JDK动态代理原理:利用拦截器(必须实现InvocationHandler)加上反射机制生成一个代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。JDK动态代理是基于接口实现代理的,如果代理对象是类,那JDK无法进行代理。

            JDK动态代理的一般步骤:

            ​ A.定义一个接口

    ​         B.创建InvocationHandler接口的实现类,实现invoke()方法。

    ​         C.调用Proxy.newProxyInstance()方法创建代理对象

    1. public interface IService{
    2. void process();
    3. }
    4. public class CoreService implements IService{
    5. public void process(){
    6. System.out.println("[target] CoreService's process()...");
    7. }
    8. }
    9. public class JdkInvocationHandler implements InvocationHandler {
    10. //目标类
    11. private Object targetObj;
    12. public JdkInvocationHandler(Object targetObj) {
    13. this.targetObj = targetObj;
    14. }
    15. @Override
    16. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    17. String name = method.getName();
    18. System.out.println("[JDK]method = " + name + ", args = " + Arrays.deepToString(args));
    19. System.out.println("[JDK]mmethod: " + name + " before doing...");
    20. //代理对象
    21. Object returnValue = method.invoke(targetObj, args);
    22. System.out.println("[JDK]mmethod: " + name + " after doing...");
    23. return returnValue;
    24. }
    25. }
    1. public class ProxyTest {
    2. public static void main(String[] args) {
    3. //目标类
    4. CoreService coreService = new CoreService();
    5. InvocationHandler jdkInvocationHandler = new JdkInvocationHandler(coreService );
    6. IService proxyService = (IService)Proxy.newProxyInstance(ProxyTest.class.getClassLoader(), new Class[]{IService.class}, jdkInvocationHandler);
    7. }

            (ii)CGLIB动态代理

            CGLIB动态代理原理:利用ASM框架,将代理对象类生成的class文件加载进来,通过修改其字节码生成子类完成对目标对象的代理。CGLIB既可以代理类,也可以代理接口。

            CGLIB动态代理的一般步骤:

            A.定义一个类

            B.创建MethodInterceptor接口的实现类,实现intercept()方法。

            C.创建CGLIB代理增强器Enhancer,通过其create()方法创建代理对象

    1. public class Service{
    2. pubilc void process(){
    3. System.out.println("[target] class Service's process()...");
    4. }
    5. }
    6. public class CustomerCglibMethodInterceptor implements MethodInterceptor {
    7. @Override
    8. public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
    9. String methodName = method.getName();
    10. System.out.println("method = " + methodName + " ,args= " + Arrays.deepToString(objects));
    11. System.out.println("[CGLIB]method = " + methodName + " ,before doing... ");
    12. // 代理对象
    13. Object invoke = methodProxy.invokeSuper(o, objects);
    14. System.out.println("[CGLIB]method = " + methodName + " ,after doing... ");
    15. return invoke;
    16. }
    17. }
    18. main{
    19. // 增强器
    20. Enhancer enhancer = new Enhancer();
    21. // 设置目标代理类
    22. enhancer.setSuperclass(Service.class);
    23. // 设置Interceptor
    24. enhancer.setCallback(new CustomerCglibMethodInterceptor());
    25. // 创建代理对象
    26. Service service = (Service)enhancer.create();
    27. service.process();
    28. }

            上面代码对所有的方法都执行同样的增强,如果我想对不同的方法实现不同的增强,例如:get开头的方法记录执行时间,set开头的方法记录详细日志。

            定义一个ConditionCallback接口,它继承MethodInterceptor并提供一个方法匹配的功能。

    1. public interface ConditionCallback extends MethodInterceptor {
    2. boolean isMatch(Method method);
    3. }

            定义两个MethodInterceptor实现类,提供两种不同的增强。

    1. public class ConditionGetMethodInterceptor implements ConditionCallback{
    2. @Override
    3. public boolean isMatch(Method method) {
    4. // 处理get方法
    5. if(method.getName().startsWith("get")){
    6. return true;
    7. }
    8. return false;
    9. }
    10. // get方法记录执行时间
    11. @Override
    12. public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
    13. long start = System.currentTimeMillis();
    14. Object invokeSuper = methodProxy.invokeSuper(o, objects);
    15. System.out.println(String.format("方法%s执行时间:%d 毫秒",method.getName(),(System.currentTimeMillis() - start)));
    16. return invokeSuper;
    17. }
    18. }
    19. public class ConditionSetMethodInterceptor implements ConditionCallback{
    20. @Override
    21. public boolean isMatch(Method method) {
    22. if(method.getName().startsWith("set")){
    23. return true;
    24. }
    25. return false;
    26. }
    27. // set方法进行日志记录
    28. @Override
    29. public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
    30. String methodName = method.getName();
    31. System.out.println("method = " + methodName + " ,args= " + Arrays.deepToString(objects));
    32. System.out.println("method = " + methodName + " ,before doing... ");
    33. Object invoke = methodProxy.invokeSuper(o, objects);
    34. System.out.println("method = " + methodName + " ,after doing... ");
    35. return invoke;
    36. }
    37. }

            定义一个CallbackFilter,在执行不同的方法时调用不同的MethodInterceptor进行增强。

    1. public class ConditionFilter implements CallbackFilter {
    2. private final Callback[] callbacks;
    3. public ConditionFilter(Callback[] callbacks){
    4. this.callbacks = callbacks;
    5. }
    6. @Override
    7. public int accept(Method method) {
    8. for (int i = 0; i < callbacks.length; i++) {
    9. if (callbacks[i] instanceof ConditionCallback){
    10. if(((ConditionCallback) callbacks[i]).isMatch(method)){
    11. return i;
    12. }
    13. }else {
    14. throw new IllegalStateException("No callback available for method " + method.getName());
    15. }
    16. }
    17. return 0;
    18. }
    19. }

             需要注意的是,如果设置了callbacks,需要与callbackFilter配套使用,不然会报错。

    1. public static void main(String[] args) {
    2. // 实现多种增强效果
    3. Callback[] callbacks = new Callback[]{new ConditionGetMethodInterceptor(),new ConditionSetMethodInterceptor()};
    4. Enhancer enhancer = new Enhancer();
    5. enhancer.setSuperclass(BasicService.class);
    6. enhancer.setCallbacks(callbacks);
    7. //和callbacks配套使用,不然会报错
    8. enhancer.setCallbackFilter(new ConditionFilter(callbacks));
    9. BasicService service = (BasicService)enhancer.create();
    10. service.getData();
    11. service.setSystemCache("zhangli",new Object());
    12. }

            通过上面的学习,我们对代理模式有了基本的了解, 也方便我们阅读Spring中关于动态代理部分的源码。

            

            (iii)JDK动态代理和CGLIB动态代理的区别?

    • JDK动态代理只能对实现了接口的类生成代理,而不能针对类。
    • CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法,并覆盖其中方法的增强,但是因为采用的是继承,所以该类或方法最好不要生成final,对于final类或方法,是无法继承的。

    二、Spring中代理的应用

            我们先来看一段代码。

            下面的A对象会实例化几次?两次

    1. @Component
    2. public class SpringProxy {
    3. @Bean
    4. public A a(){
    5. System.out.println("init A");
    6. return new A();
    7. }
    8. @Bean
    9. public B b(){
    10. a();
    11. System.out.println("init B");
    12. return new B();
    13. }
    14. }

            看控制台的打印:、

    1. init A
    2. init A
    3. init B

            可以看到a()方法被调用了两次,即A对象被创建了两次,按照我们的理解,既然我们把在a()方法上加了@Bean,那它就会生成对应的beanDefinition,相对于是Spring中的Bean了,默认情况下应该是单例的,那为什么a()方法被调用了两次(A对象实例化两次)。

            接下来,我们把类上的@Component注解由改成@Configuration注解,现在,发现a()方法只被调用了一次。这就符合我们的预期了,为什么会这样?那Spring中是如何实现的呢?

             记得上一篇文章我们已经阅读完解析@Component和@Configuration及@Bean注解的源码,好像也没有看到相关处理,除了会将全配置类的BD的属性CONFIGURATION_CLASS_ATTRIBUTE的值设置为CONFIGURATION_CLASS_FULL,属性,简洁配置类的BD的属性CONFIGURATION_CLASS_ATTRIBUTE的设置为CONFIGURATION_CLASS_LITE。(解析配置类源码分析)这其实也是Spring中代理的应用点之一,我们在上篇文章最后也提示了ConfigurationClassPostProcessor类的其中一个功能就是生成CGLIB代理对象,具体逻辑在BeanFactoryPostProcessor的接口方法postProcessBeanFactory()中实现的。话不多说,我们直接看源码吧!

    源码分析

           Spring在ConfigurationClassPostProcessor类的postProcessBeanFactory()方法中实现动态代理的,该方法是BeanFactoryPostProcessor的接口方法。

            这个方法中完成配置类进行增强,生成对应的代理对象。同时添加一个ImportAwareBeanPostProcessor类型的后置处理器到容器中。

    1. @Override
    2. public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    3. int factoryId = System.identityHashCode(beanFactory);
    4. if (this.factoriesPostProcessed.contains(factoryId)) {
    5. throw new IllegalStateException(
    6. "postProcessBeanFactory already called on this post-processor against " + beanFactory);
    7. }
    8. this.factoriesPostProcessed.add(factoryId);
    9. if (!this.registriesPostProcessed.contains(factoryId)) {
    10. // BeanDefinitionRegistryPostProcessor hook apparently not supported...
    11. // Simply call processConfigurationClasses lazily at this point then.
    12. processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
    13. }
    14. //生成代理对象
    15. // 代码块一:对配置类进行增强
    16. enhanceConfigurationClasses(beanFactory);
    17. ///添加一个ImportAwareBeanPostProcessor类型的后置处理器
    18. beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
    19. }

    (1)代码块一:enhanceConfigurationClasses(),后置处理从一个BeanFactory查找到的配置类的BeanDefinitions,然后通过ConfigurationClassEnhancer增强候选对象。

            就是将容器中的所有符合要求的配置类找到(是否全配置类),放入候选集合,然后遍历候选集合,完成对应方法的增强,同时将代理对象的class设置为BD的beanClass属性的值。

    1. /**后置处理从一个BeanFactory查找到的配置类的BeanDefinitions;
    2. * 然后通过{@link ConfigurationClassEnhancer}增强任何候选对象。
    3. * 候选状态由BeanDefinition属性元数据决定。
    4. **/
    5. public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
    6. StartupStep enhanceConfigClasses = this.applicationStartup.start("spring.context.config-classes.enhance");
    7. // 存放候选的beanDefinition(全配置类才会添加到这个集合)
    8. Map configBeanDefs = new LinkedHashMap<>();
    9. for (String beanName : beanFactory.getBeanDefinitionNames()) {
    10. BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
    11. // 候选条件属性
    12. Object configClassAttr = beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE);
    13. MethodMetadata methodMetadata = null;
    14. if (beanDef instanceof AnnotatedBeanDefinition) {
    15. // @Bean标记的方法生成的beanDefinition设置了这个值
    16. methodMetadata = ((AnnotatedBeanDefinition) beanDef).getFactoryMethodMetadata();
    17. }
    18. if ((configClassAttr != null || methodMetadata != null) && beanDef instanceof AbstractBeanDefinition) {
    19. // Configuration class (full or lite) or a configuration-derived @Bean method
    20. // -> resolve bean class at this point...
    21. AbstractBeanDefinition abd = (AbstractBeanDefinition) beanDef;
    22. if (!abd.hasBeanClass()) {
    23. try {
    24. // 确保beanClass被解析
    25. abd.resolveBeanClass(this.beanClassLoader);
    26. }
    27. catch (Throwable ex) {
    28. throw new IllegalStateException(
    29. "Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
    30. }
    31. }
    32. }
    33. //找到所有符合标准的全配置类
    34. if (ConfigurationClassUtils.CONFIGURATION_CLASS_FULL.equals(configClassAttr)) {
    35. if (!(beanDef instanceof AbstractBeanDefinition)) {
    36. throw new BeanDefinitionStoreException("Cannot enhance @Configuration bean definition '" +
    37. beanName + "' since it is not stored in an AbstractBeanDefinition subclass");
    38. }
    39. else if (logger.isInfoEnabled() && beanFactory.containsSingleton(beanName)) {
    40. logger.info("Cannot enhance @Configuration bean definition '" + beanName +
    41. "' since its singleton instance has been created too early. The typical cause " +
    42. "is a non-static @Bean method with a BeanDefinitionRegistryPostProcessor " +
    43. "return type: Consider declaring such methods as 'static'.");
    44. }
    45. //将全配置类放入map
    46. configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
    47. }
    48. }
    49. //
    50. if (configBeanDefs.isEmpty()) {
    51. // nothing to enhance -> return immediately
    52. enhanceConfigClasses.end();
    53. return;
    54. }
    55. if (IN_NATIVE_IMAGE) {
    56. throw new BeanDefinitionStoreException("@Configuration classes need to be marked as proxyBeanMethods=false. Found: " + configBeanDefs.keySet());
    57. }
    58. //创建配置类代理增强器
    59. ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
    60. //循环map,生成代理对象
    61. for (Map.Entry entry : configBeanDefs.entrySet()) {
    62. AbstractBeanDefinition beanDef = entry.getValue();
    63. // If a @Configuration class gets proxied, always proxy the target class
    64. //代理的标识,是否被代理
    65. beanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
    66. // Set enhanced subclass of the user-specified bean class
    67. //原始对象
    68. Class configClass = beanDef.getBeanClass();
    69. //CGLIB代理是基于父类实现的(继承)
    70. //代理对象
    71. // 代码二:使用CGLIB代理对配置类进行增强
    72. Class enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
    73. if (configClass != enhancedClass) {
    74. if (logger.isTraceEnabled()) {
    75. logger.trace(String.format("Replacing bean definition '%s' existing class '%s' with " +
    76. "enhanced class '%s'", entry.getKey(), configClass.getName(), enhancedClass.getName()));
    77. }
    78. //将生成的代理对象放入BD
    79. beanDef.setBeanClass(enhancedClass);
    80. }
    81. }
    82. enhanceConfigClasses.tag("classCount", () -> String.valueOf(configBeanDefs.keySet().size())).end();
    83. }

     (2)代码块二:enhance(),使用CGLIB代理对配置类进行增强。

    1. public Class enhance(Class configClass, @Nullable ClassLoader classLoader) {
    2. //判断是否被代理过
    3. //spring生成的代理类实现类EnhancedConfiguration接口
    4. if (EnhancedConfiguration.class.isAssignableFrom(configClass)) {
    5. if (logger.isDebugEnabled()) {
    6. logger.debug(String.format("Ignoring request to enhance %s as it has " +
    7. "already been enhanced. This usually indicates that more than one " +
    8. "ConfigurationClassPostProcessor has been registered (e.g. via " +
    9. "). This is harmless, but you may " +
    10. "want check your configuration and remove one CCPP if possible",
    11. configClass.getName()));
    12. }
    13. return configClass;
    14. }
    15. // 代码三:创建代理对象对应的class
    16. Class enhancedClass = createClass(newEnhancer(configClass, classLoader));
    17. if (logger.isTraceEnabled()) {
    18. logger.trace(String.format("Successfully enhanced %s; enhanced class name is: %s",
    19. configClass.getName(), enhancedClass.getName()));
    20. }
    21. return enhancedClass;
    22. }

    (3)代码块三:createClass(),创建代理增强器完成代理,并返回代理对象的class。

    1. private Class createClass(Enhancer enhancer) {
    2. Class subclass = enhancer.createClass();
    3. // Registering callbacks statically (as opposed to thread-local)
    4. // is critical for usage in an OSGi environment (SPR-5932)...
    5. // 代码四:注册回调函数
    6. Enhancer.registerStaticCallbacks(subclass, CALLBACKS);
    7. return subclass;
    8. }

    (4)代码块四:registerStaticCallbacks(),注册回调函数。

            根据不同方法调用不同的Callback完成方法的增强。

    • BeanMethodInterceptor 对方法的Class类型不属于Object.class,且方法名为setFactoryBean(),同时方法上有@Bean注解的方法进行增强
    • BeanFactoryAwareMethodInterceptor 对方法名为setFactoryBean()且方法类型为BeanFactoryAware.class的方法进行增强。
    • NoOp.INSTANCE:无操作。
    1. // 回调函数都是无状态的
    2. private static final Callback[] CALLBACKS = new Callback[] {
    3. new BeanMethodInterceptor(),
    4. new BeanFactoryAwareMethodInterceptor(),
    5. NoOp.INSTANCE
    6. };
    7. private static class BeanMethodInterceptor implements MethodInterceptor, ConditionalCallback {
    8. ……
    9. //Class类型不属于Object.class,不是setFactoryBean()且方法上有@Bean注解
    10. @Override
    11. public boolean isMatch(Method candidateMethod) {
    12. return (candidateMethod.getDeclaringClass() != Object.class &&
    13. !BeanFactoryAwareMethodInterceptor.isSetBeanFactory(candidateMethod) &&
    14. BeanAnnotationHelper.isBeanAnnotated(candidateMethod));
    15. }
    16. ……
    17. }
    18. private static class BeanFactoryAwareMethodInterceptor implements MethodInterceptor, ConditionalCallback {
    19. ……
    20. // setBeanFactory()方法才会执行这部分的增强
    21. @Override
    22. public boolean isMatch(Method candidateMethod) {
    23. return isSetBeanFactory(candidateMethod);
    24. }
    25. // 方法名为setBeanFactory()且方法类型为BeanFactoryAware,才会执行这部分的增强
    26. public static boolean isSetBeanFactory(Method candidateMethod) {
    27. return (candidateMethod.getName().equals("setBeanFactory") &&
    28. candidateMethod.getParameterCount() == 1 &&
    29. BeanFactory.class == candidateMethod.getParameterTypes()[0] &&
    30. BeanFactoryAware.class.isAssignableFrom(candidateMethod.getDeclaringClass()));
    31. }
    32. ……
    33. }

    1. public static void registerStaticCallbacks(Class generatedClass, Callback[] callbacks) {
    2. setCallbacksHelper(generatedClass, callbacks, "CGLIB$SET_STATIC_CALLBACKS");
    3. }
    4. private static void setCallbacksHelper(Class type, Callback[] callbacks, String methodName) {
    5. try {
    6. // Callback中methodName对应的方法
    7. Method setter = getCallbacksSetter(type, methodName);
    8. setter.invoke((Object)null, callbacks);
    9. } catch (NoSuchMethodException var4) {
    10. throw new IllegalArgumentException(type + " is not an enhanced class");
    11. } catch (IllegalAccessException var5) {
    12. throw new CodeGenerationException(var5);
    13. } catch (InvocationTargetException var6) {
    14. throw new CodeGenerationException(var6);
    15. }
    16. }
    17. private static Method getCallbacksSetter(Class type, String methodName) throws NoSuchMethodException {
    18. return type.getDeclaredMethod(methodName, Callback[].class);
    19. }

     (5)代码块五:newEnhancer(),创建CGLIB增强器完成代理。

    1. //代码四:创建CGLIB代理增强器实例
    2. /**
    3. * Creates a new CGLIB {@link Enhancer} instance.
    4. */
    5. private Enhancer newEnhancer(Class configSuperClass, @Nullable ClassLoader classLoader) {
    6. Enhancer enhancer = new Enhancer();
    7. enhancer.setSuperclass(configSuperClass);
    8. enhancer.setInterfaces(new Class[] {EnhancedConfiguration.class});
    9. enhancer.setUseFactory(false);
    10. enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
    11. enhancer.setStrategy(new BeanFactoryAwareGeneratorStrategy(classLoader));
    12. //设置用于增强CallbackFilter
    13. enhancer.setCallbackFilter(CALLBACK_FILTER);
    14. enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes());
    15. return enhancer;
    16. }

            这里CallbackFilter的作用我们在代码演示里面大概知道其用途了。

    1. private static class ConditionalCallbackFilter implements CallbackFilter {
    2. private final Callback[] callbacks;
    3. private final Class[] callbackTypes;
    4. // callbacks数组赋值
    5. public ConditionalCallbackFilter(Callback[] callbacks) {
    6. this.callbacks = callbacks;
    7. this.callbackTypes = new Class[callbacks.length];
    8. for (int i = 0; i < callbacks.length; i++) {
    9. this.callbackTypes[i] = callbacks[i].getClass();
    10. }
    11. }
    12. // 根据不同的方法匹配不同的callback
    13. @Override
    14. public int accept(Method method) {
    15. for (int i = 0; i < this.callbacks.length; i++) {
    16. Callback callback = this.callbacks[i];
    17. if (!(callback instanceof ConditionalCallback) || ((ConditionalCallback) callback).isMatch(method)) {
    18. return i;
    19. }
    20. }
    21. throw new IllegalStateException("No callback available for method " + method.getName());
    22. }
    23. public Class[] getCallbackTypes() {
    24. return this.callbackTypes;
    25. }
    26. }

    三、BeanMethodInterceptor源码分析

            通过上面对CALLBACKS数组简单了解,其中包含一个BeanMethodInterceptor实例,也了解了系统中注入的两个MethodInterceptor的isMatch()方法,使用BeanMethodInterceptor进行的情况居多,它会对大部分@Bean方法进行增强。

            方法大致总结为:

             1)根据方法名推断beanName。默认值为方法名称,如果有配置name属性,只要一个值时为这个唯一值,有多个值时,取下标为0的值 。

            2)获取Bean方法对应的代理模式,默认为NO。

            3)检查所请求的bean是否是FactoryBean。如果是,创建一个子类完成代理。如果FactoryBean或其接口方法getObject()有一个被final修饰,如果是,存在如下两种情况。

            a.方法返回值类型为接口,通过JDK动态代理完成方法增强。

            b.如果返回值类型不是接口,无法完成代理,直接直接返回FactoryBean

            否则通过CGLIB代理完成方法增强。

            4)判断当前创建Bean的方法与实际调用的方法一致。比较线程本地变量存储的factoryMethod与当前方法是否一致。(方法名和参数列表一致)

            a.如果一致,通过CGLIB代理完成方法增强,会执行父类方法,即@Bean方法里面实例化对象的方法。

             b.如果不一致,根据当前调用方法对应的beanName和方法参数通过getBean获取相关实例beanInstance,设置该实例与factoryMethod对应的bean的依赖关系。返回这个实例对象。 

    1. private static class BeanMethodInterceptor implements MethodInterceptor, ConditionalCallback {
    2. @Override
    3. @Nullable
    4. public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object[] beanMethodArgs,
    5. MethodProxy cglibMethodProxy) throws Throwable {
    6. ConfigurableBeanFactory beanFactory = getBeanFactory(enhancedConfigInstance);
    7. // 获取方法对应的beanName
    8. String beanName = BeanAnnotationHelper.determineBeanNameFor(beanMethod);
    9. // Determine whether this bean is a scoped-proxy
    10. if (BeanAnnotationHelper.isScopedProxy(beanMethod)) {
    11. String scopedBeanName = ScopedProxyCreator.getTargetBeanName(beanName);
    12. if (beanFactory.isCurrentlyInCreation(scopedBeanName)) {
    13. beanName = scopedBeanName;
    14. }
    15. }
    16. // 检查所请求的bean是否是FactoryBean。如果是,创建一个子类
    17. if (factoryContainsBean(beanFactory, BeanFactory.FACTORY_BEAN_PREFIX + beanName) &&
    18. factoryContainsBean(beanFactory, beanName)) {
    19. Object factoryBean = beanFactory.getBean(BeanFactory.FACTORY_BEAN_PREFIX + beanName);
    20. if (factoryBean instanceof ScopedProxyFactoryBean) {
    21. // Scoped proxy factory beans are a special case and should not be further proxied
    22. //有作用域的代理工厂bean是一种特殊情况,不应该被进一步代理
    23. }
    24. else {
    25. // It is a candidate FactoryBean - go ahead with enhancement
    26. // 代码六:对候选FactoryBean进行增强
    27. return enhanceFactoryBean(factoryBean, beanMethod.getReturnType(), beanFactory, beanName);
    28. }
    29. }
    30. //代码块九:当前创建Bean的方法与实际调用的方法一致
    31. if (isCurrentlyInvokedFactoryMethod(beanMethod)) {
    32. // The factory is calling the bean method in order to instantiate and register the bean
    33. // (i.e. via a getBean() call) -> invoke the super implementation of the method to actually
    34. // create the bean instance.
    35. if (logger.isInfoEnabled() &&
    36. BeanFactoryPostProcessor.class.isAssignableFrom(beanMethod.getReturnType())) {
    37. logger.info(String.format("@Bean method %s.%s is non-static and returns an object " +
    38. "assignable to Spring's BeanFactoryPostProcessor interface. This will " +
    39. "result in a failure to process annotations such as @Autowired, " +
    40. "@Resource and @PostConstruct within the method's declaring " +
    41. "@Configuration class. Add the 'static' modifier to this method to avoid " +
    42. "these container lifecycle issues; see @Bean javadoc for complete details.",
    43. beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName()));
    44. }
    45. //调用父类方法创建bean
    46. return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);
    47. }
    48. //当前创建bean的方法与实际调用的方法不一致
    49. /**例如:
    50. * f(){
    51. * e();
    52. * }
    53. * 在执行f()方法中调用了e()方法;
    54. * 当前执行的是f()方法,在执行到e()时,实际调用了e(),就会执行resolveBeanReference
    55. * 类似于beanMethod就是当前执行方法栈的栈顶方法,f()是这个方法栈
    56. */
    57. return resolveBeanReference(beanMethod, beanMethodArgs, beanFactory, beanName);
    58. }

    (1)代码块六:enhanceFactoryBean(),完成通过FactroyBean方式创建的对象的代理。

            这个方法大概总结为:

          1) FactoryBean类及其getObject()方法是否被final修饰,如果这两个其中一个被final修饰。

                    a.如果是方法的返回值是接口类型,则通过JDK动态代理完成方法增强

                    b.不是接口类型,无法进行代理,直接返回FactoryBean。

            2)如果不被final修饰,通过CGLIB代理实现方法增强。

    1. private Object enhanceFactoryBean(final Object factoryBean, Class exposedType,
    2. final ConfigurableBeanFactory beanFactory, final String beanName) {
    3. try {
    4. Class clazz = factoryBean.getClass();
    5. // 类是否被final修饰
    6. boolean finalClass = Modifier.isFinal(clazz.getModifiers());
    7. // factoryBean的getObject()方法是否被final修饰
    8. boolean finalMethod = Modifier.isFinal(clazz.getMethod("getObject").getModifiers());
    9. if (finalClass || finalMethod) {
    10. // 如果是接口
    11. if (exposedType.isInterface()) {
    12. if (logger.isTraceEnabled()) {
    13. logger.trace("Creating interface proxy for FactoryBean '" + beanName + "' of type [" +
    14. clazz.getName() + "] for use within another @Bean method because its " +
    15. (finalClass ? "implementation class" : "getObject() method") +
    16. " is final: Otherwise a getObject() call would not be routed to the factory.");
    17. }
    18. // 代码七:通过FactoryBean创建接口类型的代理
    19. return createInterfaceProxyForFactoryBean(factoryBean, exposedType, beanFactory, beanName);
    20. }
    21. else {
    22. // 打印日志,final类型的类或final无法进行代理
    23. if (logger.isDebugEnabled()) {
    24. logger.debug("Unable to proxy FactoryBean '" + beanName + "' of type [" +
    25. clazz.getName() + "] for use within another @Bean method because its " +
    26. (finalClass ? "implementation class" : "getObject() method") +
    27. " is final: A getObject() call will NOT be routed to the factory. " +
    28. "Consider declaring the return type as a FactoryBean interface.");
    29. }
    30. return factoryBean;
    31. }
    32. }
    33. }
    34. catch (NoSuchMethodException ex) {
    35. // No getObject() method -> shouldn't happen, but as long as nobody is trying to call it...
    36. }
    37. // 代码八:通过FactoryBean创建CGLIB类型的代理
    38. return createCglibProxyForFactoryBean(factoryBean, beanFactory, beanName);
    39. }

    (2) 代码七:createInterfaceProxyForFactoryBean(),通过JDK动态代理完成增强。

    1. // 通过FactoryBean创建接口类型的代理
    2. private Object createInterfaceProxyForFactoryBean(final Object factoryBean, Class interfaceType,
    3. final ConfigurableBeanFactory beanFactory, final String beanName) {
    4. //通过JDK动态代理实现对目标接口的增强
    5. return Proxy.newProxyInstance(
    6. factoryBean.getClass().getClassLoader(), new Class[] {interfaceType},
    7. (proxy, method, args) -> {
    8. if (method.getName().equals("getObject") && args == null) {
    9. return beanFactory.getBean(beanName);
    10. }
    11. return ReflectionUtils.invokeMethod(method, factoryBean, args);
    12. });
    13. }

    (3)代码块八:createCglibProxyForFactoryBean(),通过CGLIB代理完成增强。

    1. private Object createCglibProxyForFactoryBean(final Object factoryBean,
    2. final ConfigurableBeanFactory beanFactory, final String beanName) {
    3. // 创建CGLIB增强器
    4. Enhancer enhancer = new Enhancer();
    5. enhancer.setSuperclass(factoryBean.getClass());
    6. enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
    7. enhancer.setCallbackType(MethodInterceptor.class);
    8. // Ideally create enhanced FactoryBean proxy without constructor side effects,
    9. // analogous to AOP proxy creation in ObjenesisCglibAopProxy...
    10. Class fbClass = enhancer.createClass();
    11. Object fbProxy = null;
    12. // SpringObjenesis
    13. // spring特定变体,提供基于{@code Class}键而不是类名的缓存;
    14. // 就是通过Class可以获取对应的缓存实例
    15. // 从objenesis缓存获取对象
    16. if (objenesis.isWorthTrying()) {
    17. try {
    18. fbProxy = objenesis.newInstance(fbClass, enhancer.getUseCache());
    19. }
    20. catch (ObjenesisException ex) {
    21. logger.debug("Unable to instantiate enhanced FactoryBean using Objenesis, " +
    22. "falling back to regular construction", ex);
    23. }
    24. }
    25. if (fbProxy == null) {
    26. try {
    27. // 通过无参构造器创建对象
    28. fbProxy = ReflectionUtils.accessibleConstructor(fbClass).newInstance();
    29. }
    30. catch (Throwable ex) {
    31. throw new IllegalStateException("Unable to instantiate enhanced FactoryBean using Objenesis, " +
    32. "and regular FactoryBean instantiation via default constructor fails as well", ex);
    33. }
    34. }
    35. ((Factory) fbProxy).setCallback(0, (MethodInterceptor) (obj, method, args, proxy) -> {
    36. if (method.getName().equals("getObject") && args.length == 0) {
    37. return beanFactory.getBean(beanName);
    38. }
    39. return proxy.invoke(factoryBean, args);
    40. });
    41. return fbProxy;
    42. }

    (4)代码块九:isCurrentlyInvokedFactoryMethod(),当前创建Bean的FactoryMethod与实际调用的方法是否一致。

           我们需要明白什么时候会执行@Bean标记的方法?

            在实例对象的时候,@Bean标记的方法是被作为FactoryMethod创建实例的一种。最终都是会调用SimpleInstantiationStrategy的实例化方法instantiate()进行对象的实例化,

    1. protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
    2. ……
    3. if (mbd.getFactoryMethodName() != null) {
    4. // 实例化对象的工厂方法也存在重载的情况,推断工厂方法的逻辑与推断构造器的逻辑类似
    5. return instantiateUsingFactoryMethod(beanName, mbd, args);
    6. }
    7. ……
    8. }

              而SimpleInstantiationStrategy类维护了一个线程本地变量currentlyInvokedFactoryMethod,用来存储当前线程执行的FactoryMethod,实例化方法instantiate()中会给这个变量设置值。

    1. public class SimpleInstantiationStrategy implements InstantiationStrategy {
    2. //当前线程执行的FactoryMethod
    3. private static final ThreadLocal currentlyInvokedFactoryMethod = new ThreadLocal<>();
    4. @Override
    5. public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
    6. @Nullable Object factoryBean, final Method factoryMethod, Object... args) {
    7. // 设置线程本地变量值
    8. currentlyInvokedFactoryMethod.set(factoryMethod);
    9. Object result = factoryMethod.invoke(factoryBean, args);
    10. if (result == null) {
    11. result = new NullBean();
    12. }
    13. return result;
    14. }
    15. }

            比较当前调用方法与线程本地变量存储的factoryMethod的方法名称及形参列表(形参个数及形参类型都一致) 是否一致。

    1. // 判断method与当前的FactoryMethod是否相同
    2. private boolean isCurrentlyInvokedFactoryMethod(Method method) {
    3. // 当前创建bean对应的方法(@Bean标记的方法名会被作为FactoryMethod保存在缓存中)
    4. Method currentlyInvoked = SimpleInstantiationStrategy.getCurrentlyInvokedFactoryMethod();
    5. // 方法名和参数列表(个数和参数类型)相同
    6. return (currentlyInvoked != null && method.getName().equals(currentlyInvoked.getName()) &&
    7. Arrays.equals(method.getParameterTypes(), currentlyInvoked.getParameterTypes()));
    8. }

            如果一致,使用CGLIB代理,就会执行父类方法。 

    (5)代码块十:resolveBeanReference(),解决对象引用。

            当前创建bean的方法与实际调用的方法不一致时,会进入这个方法,我们看到,这里获取beanName对应的实例是通过getBean(),而不是调用实例化方法instantiate(),所以不会多次实例化。

            这个方法大概总结为:

            1)判断当前对象beanName是否正在创建,如果是,临时设置创建中的状态为 false,以避免异常。

            2)获取方法参数数组,如果方法参数数组中有一个值为null,舍弃参数,因为初始化或获取对应的实例时,不运行构造参数模棱两可。

            3)如果是参数不满足要求,获取(或创建,看容器中是否存在)无参实例。满足要求则获取(或创建,看容器中是否存在)有参实例。

            4)如果获取的实例beanInstance不为null,但方法返回值类型与实例类型不匹配,抛出异常(IllegalStateException)。

            5)获取线程本地变量存储的factoryMethod,设置当前实例beanInstance对应的beanName与其的依赖关系。返回beanInstance。(相对于beanInstance是factoryMethod对应的bean的一个属性。)

            6)设置创建中的状态的值。

    1. private Object resolveBeanReference(Method beanMethod, Object[] beanMethodArgs,
    2. ConfigurableBeanFactory beanFactory, String beanName) {
    3. // The user (i.e. not the factory) is requesting this bean through a call to
    4. // the bean method, direct or indirect. The bean may have already been marked
    5. // as 'in creation' in certain autowiring scenarios; if so, temporarily set
    6. // the in-creation status to false in order to avoid an exception.
    7. // 是否正在创建,false
    8. boolean alreadyInCreation = beanFactory.isCurrentlyInCreation(beanName);
    9. try {
    10. if (alreadyInCreation) {
    11. beanFactory.setCurrentlyInCreation(beanName, false);
    12. }
    13. boolean useArgs = !ObjectUtils.isEmpty(beanMethodArgs);
    14. // 参数不为空且是单例对象
    15. if (useArgs && beanFactory.isSingleton(beanName)) {
    16. // Stubbed null arguments just for reference purposes,
    17. // expecting them to be autowired for regular singleton references?
    18. // A safe assumption since @Bean singleton arguments cannot be optional...
    19. for (Object arg : beanMethodArgs) {
    20. if (arg == null) {
    21. useArgs = false;
    22. break;
    23. }
    24. }
    25. }
    26. //不是直接调用父类方法(new),而是通过beanFactory.getBean(beanName)
    27. // 要不要传参,如果beanMethodArgs包含有null值,调用无参的方法获取bean
    28. // 为什么不会实例化多次的原因,先去从容器中获取
    29. Object beanInstance = (useArgs ? beanFactory.getBean(beanName, beanMethodArgs) :
    30. beanFactory.getBean(beanName));
    31. if (!ClassUtils.isAssignableValue(beanMethod.getReturnType(), beanInstance)) {
    32. // Detect package-protected NullBean instance through equals(null) check
    33. if (beanInstance.equals(null)) {
    34. if (logger.isDebugEnabled()) {
    35. logger.debug(String.format("@Bean method %s.%s called as bean reference " +
    36. "for type [%s] returned null bean; resolving to null value.",
    37. beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName(),
    38. beanMethod.getReturnType().getName()));
    39. }
    40. beanInstance = null;
    41. }
    42. else {
    43. String msg = String.format("@Bean method %s.%s called as bean reference " +
    44. "for type [%s] but overridden by non-compatible bean instance of type [%s].",
    45. beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName(),
    46. beanMethod.getReturnType().getName(), beanInstance.getClass().getName());
    47. try {
    48. BeanDefinition beanDefinition = beanFactory.getMergedBeanDefinition(beanName);
    49. msg += " Overriding bean of same name declared in: " + beanDefinition.getResourceDescription();
    50. }
    51. catch (NoSuchBeanDefinitionException ex) {
    52. // Ignore - simply no detailed message then.
    53. }
    54. throw new IllegalStateException(msg);
    55. }
    56. }
    57. Method currentlyInvoked = SimpleInstantiationStrategy.getCurrentlyInvokedFactoryMethod();
    58. if (currentlyInvoked != null) {
    59. // 默认为方法名,如果自定义了name,使用自定义的name,如果自定义了多个name,取下标为0的那个作为name
    60. String outerBeanName = BeanAnnotationHelper.determineBeanNameFor(currentlyInvoked);
    61. // 维护依赖关系集合,beanName需要被添加到哪些bean(dependentBeanMap),outerBeanName需要哪些依赖(dependenciesForBean)
    62. beanFactory.registerDependentBean(beanName, outerBeanName);
    63. }
    64. return beanInstance;
    65. }
    66. finally {
    67. // false
    68. if (alreadyInCreation) {
    69. // 设置为正在创建
    70. beanFactory.setCurrentlyInCreation(beanName, true);
    71. }
    72. }
    73. }

    (6)BeanFactoryAwareMethodInterceptor实现的方法增强。

            如果方法名称为setBeanFactory()且返回值类型为BeanFactoryAware.class,直接调用父类的setBeanFactory()方法,不进行任何增强。

    1. private static class BeanFactoryAwareMethodInterceptor implements MethodInterceptor, ConditionalCallback {
    2. @Override
    3. @Nullable
    4. public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
    5. // 根据class类型和name查找field
    6. Field field = ReflectionUtils.findField(obj.getClass(), BEAN_FACTORY_FIELD);
    7. Assert.state(field != null, "Unable to find generated BeanFactory field");
    8. field.set(obj, args[0]);
    9. // Does the actual (non-CGLIB) superclass implement BeanFactoryAware?
    10. // If so, call its setBeanFactory() method. If not, just exit.
    11. if (BeanFactoryAware.class.isAssignableFrom(ClassUtils.getUserClass(obj.getClass().getSuperclass()))) {
    12. //调用BeanFactoryAware.setBeanFactory()
    13. return proxy.invokeSuper(obj, args);
    14. }
    15. return null;
    16. }
    17. }

     (7)代码分析

            看完源码,我们对如下代码进行分析。

    1. @Configuration
    2. public class SpringProxy {
    3. @Bean
    4. public A a(){
    5. System.out.println("init A");
    6. return new A();
    7. }
    8. @Bean
    9. public B b(){
    10. a();
    11. System.out.println("init B");
    12. return new B();
    13. }
    14. }

            1)A对象实例化时,通过工厂方法实例化 A对象,把当前线程本地变量currentlyInvokedFactoryMethod赋值为a(),进入a()方法,判断当前调用方法(a())是否与线程本地变量存储的factoryMethod一致,一致,执行CGLIB代理,就会调用父类方法进行实例化。(new A())。

            2)B对象实例化时,通过工厂方法实例化 B对象,把当前线程本地变量currentlyInvokedFactoryMethod赋值为b(),进入b()方法,判断当前调用方法(b())是否与线程本地变量存储的factoryMethod一致,一致,执行CGLIB代理,就会调用父类方法进行实例化。(a())。

            3)B对象实例化调用父类方法时,会执行a()方法,判断当前调用方法(a())是否与线程本地变量存储的factoryMethod(b())一致,不一致,获取方法名和方法参数,通过getBean()获取方法对应的实例对象beanInstance,并把该实例作为当前线程本地变量存储的factoryMethod(b())对应的bean的一个依赖,并进行维护依赖关系相关集合。返回获取的beanInstance。

            4)a()返回后,继续执行(b())父类的方法(new B()),完成B对象的实例化。

    四、总结 

            我们知道java类实例化的基本流程是先将.java文件编译成.class文件,然后通过类加载器加载class文件到jvm中,jvm将class解析成字节码(byte)。而动态代理则是直接生成对应的字节码(byte),在需要创建大量类的系统中,使用动态代理可以防止类爆炸。

            通过前面的源码阅读,@Configuration注解标识的类会使用代理,可以保证生成的对象是单例的,我们在开发中可以好好利用这个特性。

  • 相关阅读:
    代码随想录Day19 LeetCode T669修剪二叉搜索树 LeetCode T108将有序数组转化为二叉搜索树 T538 把二叉搜索树转化为累加树
    一种改进多旋翼无人机动态仿真的模块化仿真环境研究(Matlab代码实现)
    Android 开发学习(三)
    重磅 | 擎创参与制定的首个金融机构数据治理标准已发布
    软信天成:助力某制造企业建设产品主数据管理平台案例分享
    javacpp gradle集成
    vue项目打包部署流程
    2022年服装进销存软件排行榜重磅出炉!
    MATLAB m文件格式化
    python工具方法37 voc数据统计分析(box聚类、box散点图、类别频率统计、box面积统计)
  • 原文地址:https://blog.csdn.net/ZHANGLI_WORB/article/details/133935714