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<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<String, AbstractBeanDefinition>();
        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 " +
                        "<context:annotation-config>). 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呢

还是两次

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容