cglib

当我们在Appconfig上不加@Confaugration时,如果

UserService.java

public class UserService {
    public UserService(){
        System.out.println("init UserService");
    }
}

OrederService.java

public class OrderService {
}

Appconfig.java

//@Configuration
@ComponentScan("com.suntong.hello")
public class Appconfig {
    @Bean
    public UserService userService(){
        return new UserService();
    }

    @Bean
    public OrderService orderService(){
        userService();
        return new OrderService();
    }

}

Test.java

public class Test {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext annotationConfigApplicationContext =
                new AnnotationConfigApplicationContext(Appconfig.class);

//这句没有也行,不会影响初始化
        System.out.println(annotationConfigApplicationContext.getBean(OrderService.class).getClass().getName());
    }
}

此时没有@Configuration注解,我们
打印出来的时两次init UserService

放开注解

就剩一次了,说明UserService被改变了

我们获取一下Appconfig类,看一看加上@Configuration后,Appconfig还是不是原先的类

Appconfig appconfig = annotationConfigApplicationContext.getBean(Appconfig.class);

断点调试

已经被代理了

UserService和OrderService还是原先的模样

如何实现一个cglib代理?

可以参考Spring中的代码

ctrl+shift+alt+N 查找类 ConfigurationClassPostPrpcessor

再进入ConfigurationClassEnhancer

ctrl+F12查找方法

/**
     * Creates a new CGLIB {@link Enhancer} instance.
     */
    private Enhancer newEnhancer(Class superclass, ClassLoader classLoader) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(superclass);
        enhancer.setInterfaces(new Class[] {EnhancedConfiguration.class});
        enhancer.setUseFactory(false);
        enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
        enhancer.setStrategy(new BeanFactoryAwareGeneratorStrategy(classLoader));
        enhancer.setCallbackFilter(CALLBACK_FILTER);
        enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes());
        return enhancer;
    }

Enhancer类再cglib包下

父类的话,想代理哪个类就用哪个类

第三行第四行不用接口,不需要

setStrategy不需要,增强属性

后面两个为过滤方法,就是增强

setCallbackFilter复杂,我们只用setCallBack

package org.springframework.cglib.proxy;

public interface Callback {
}

Callback为一个接口

ctrl+alt+B找到实现类

package org.springframework.cglib.proxy;

import java.lang.reflect.Method;

public interface MethodInterceptor extends Callback {
    Object intercept(Object var1, Method var2, Object[] var3, MethodProxy var4) throws Throwable;
}

还是一个接口

自己实现

import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class SuntongMethodInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("interceptor cglib");
        return methodProxy.invokeSuper(o,objects);
    }
}

最后的代理生成,调用UserService新增的方法query

public static void main(String[] args) {
//        AnnotationConfigApplicationContext annotationConfigApplicationContext =
//                new AnnotationConfigApplicationContext(Appconfig.class);
//        Appconfig appconfig = annotationConfigApplicationContext.getBean(Appconfig.class);
//        UserService userService = annotationConfigApplicationContext.getBean(UserService.class);
//        OrderService orderService = annotationConfigApplicationContext.getBean(OrderService.class);
//        System.out.println(annotationConfigApplicationContext.getBean(OrderService.class).getClass().getName());
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(UserService.class);

        enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);

        enhancer.setCallback(new SuntongMethodInterceptor());
        UserService userService = (UserService) enhancer.create();
        userService.query();

    }

完成代理增强

小结

所以之前OrderService中的userService方法根本就没有调用到UserService

什么时候解析的@Configuration

AnnotationConfigApplicationContextrefresh方法invokeBeanFactoryPostProcessors(beanFactory);方法下invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors())方法

// Now, invoke the postProcessBeanFactory callback of all processors handled so far.
invokeBeanFactoryPostProcessors(registryPostProcessors, beanFactory);

执行BeanFactoryPostProcessor的回调
前面执行的时BeanFactoryPostProcessor子类BeanDefinitionRegistryPostProcessor的回调

点进去

for (BeanFactoryPostProcessor postProcessor : postProcessors) {
            postProcessor.postProcessBeanFactory(beanFactory);
        }

点进去

public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        int factoryId = System.identityHashCode(beanFactory);
        if (this.factoriesPostProcessed.contains(factoryId)) {
            throw new IllegalStateException(
                    "postProcessBeanFactory already called on this post-processor against " + beanFactory);
        }
        this.factoriesPostProcessed.add(factoryId);
        if (!this.registriesPostProcessed.contains(factoryId)) {
            // BeanDefinitionRegistryPostProcessor hook apparently not supported...
            // Simply call processConfigurationClasses lazily at this point then.
            processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
        }
        enhanceConfigurationClasses(beanFactory);
    }

点进去enhanceConfigurationClasses(beanFactory)

public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
        Map configBeanDefs = new LinkedHashMap();
        for (String beanName : beanFactory.getBeanDefinitionNames()) {
            BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
            if (ConfigurationClassUtils.isFullConfigurationClass(beanDef)) {
                if (!(beanDef instanceof AbstractBeanDefinition)) {
                    throw new BeanDefinitionStoreException("Cannot enhance @Configuration bean definition '" +
                            beanName + "' since it is not stored in an AbstractBeanDefinition subclass");
                }
                configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
            }
        }

加了@Configuration的类才能进入if判断isFullConfigurationClass全注解

加条件断点

BeanDefinition是用来描述Bean的

进入if判断(因为有@Configuration注解)

回到之前的Map,因为spring类有很多,会对map进行遍历看是否有注解

点进去

public Class enhance(Class configClass, ClassLoader classLoader) {
        if (EnhancedConfiguration.class.isAssignableFrom(configClass)) {
            if (logger.isDebugEnabled()) {
                logger.debug(String.format("Ignoring request to enhance %s as it has " +
                        "already been enhanced. This usually indicates that more than one " +
                        "ConfigurationClassPostProcessor has been registered (e.g. via " +
                        "). This is harmless, but you may " +
                        "want check your configuration and remove one CCPP if possible",
                        configClass.getName()));
            }
            return configClass;
        }
        Class enhancedClass = createClass(newEnhancer(configClass, classLoader));
        if (logger.isDebugEnabled()) {
            logger.debug(String.format("Successfully enhanced %s; enhanced class name is: %s",
                    configClass.getName(), enhancedClass.getName()));
        }
        return enhancedClass;
    }
if (EnhancedConfiguration.class.isAssignableFrom(configClass))

判断是否被代理过

因为底层会添加一个代理接口

这时候就很熟悉了,这里就是刚才我们自己实现的代理用的代码

打上断点

BeanFactoryAwareGeneratorStrategy中有一个transfom方法增强属性

看一下过滤器
enhancer.setCallbackFilter(CALLBACK_FILTER);

3个过滤器,用了一个数组

private static final Callback[] CALLBACKS = new Callback[] {
            new BeanMethodInterceptor(),
//设置一个beanFactory
            new BeanFactoryAwareMethodInterceptor(),
            NoOp.INSTANCE
    };

看第一个,点进去

@Override
        public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object[] beanMethodArgs,
                    MethodProxy cglibMethodProxy) throws Throwable {        

一个判断

if (isCurrentlyInvokedFactoryMethod(beanMethod)) {

这里就能看开始的问题了,比如第一次访问就new一个对象,不然就else

而Spring看执行的方法名是否相同,相同就new,不相同就getBean

比如之前我们的方法名时orderService,而内部要调用userService,所以直接getBean了,就没有实例对象

if (isCurrentlyInvokedFactoryMethod(beanMethod)) {
                // The factory is calling the bean method in order to instantiate and register the bean
                // (i.e. via a getBean() call) -> invoke the super implementation of the method to actually
                // create the bean instance.
                if (BeanFactoryPostProcessor.class.isAssignableFrom(beanMethod.getReturnType())) {
                    logger.warn(String.format("@Bean method %s.%s is non-static and returns an object " +
                            "assignable to Spring's BeanFactoryPostProcessor interface. This will " +
                            "result in a failure to process annotations such as @Autowired, " +
                            "@Resource and @PostConstruct within the method's declaring " +
                            "@Configuration class. Add the 'static' modifier to this method to avoid " +
                            "these container lifecycle issues; see @Bean javadoc for complete details.",
                            beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName()));
                }
                return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);
            }
            else {
                // The user (i.e. not the factory) is requesting this bean through a
                // call to the bean method, direct or indirect. The bean may have already been
                // marked as 'in creation' in certain autowiring scenarios; if so, temporarily
                // set the in-creation status to false in order to avoid an exception.
                boolean alreadyInCreation = beanFactory.isCurrentlyInCreation(beanName);
                try {
                    if (alreadyInCreation) {
                        beanFactory.setCurrentlyInCreation(beanName, false);
                    }
                    Object beanInstance = (!ObjectUtils.isEmpty(beanMethodArgs) ?
                            beanFactory.getBean(beanName, beanMethodArgs) : beanFactory.getBean(beanName));
                    if (beanInstance != null && !ClassUtils.isAssignableValue(beanMethod.getReturnType(), beanInstance)) {
                        String msg = String.format("@Bean method %s.%s called as a bean reference " +
                                    "for type [%s] but overridden by non-compatible bean instance of type [%s].",
                                    beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName(),
                                    beanMethod.getReturnType().getName(), beanInstance.getClass().getName());
                        try {
                            BeanDefinition beanDefinition = beanFactory.getMergedBeanDefinition(beanName);
                            msg += " Overriding bean of same name declared in: " + beanDefinition.getResourceDescription();
                        }
                        catch (NoSuchBeanDefinitionException ex) {
                            // Ignore - simply no detailed message then.
                        }
                        throw new IllegalStateException(msg);
                    }
                    return beanInstance;
                }
                finally {
                    if (alreadyInCreation) {
                        beanFactory.setCurrentlyInCreation(beanName, true);
                    }
                }
            }

返回父类的方法

点这个,跳过去

又实例了一个OrderService

再来第三遍

直接进入了else

判断是否正在创建

已经创建完了

这样就不会二次创建了

FactoryBean和BeanFactory

BeanFactory就是产生存储Bean的容器。

FactoryBean是一种特殊的bean,它的getObject方法可以返回一个对象,如果你用过spring-mybatis的话,你有没有想过为什么一个mapper接口最后可以变成一个对象进行数据库的操作?原因是mybatis底层把我们的mapper定义成一个FactoryBean,然后在getObject方法中通过动态代理生成一个实力可操作的代理对象保存在Factory容器中。

如果给UserService加上static呢

还是两次

你可能感兴趣的:(cglib)