zoukankan      html  css  js  c++  java
  • spring aop 源码分析(三) @Scope注解创建代理对象

    一.源码环境的搭建:

    @Component
    @Scope(scopeName = ConfigurableBeanFactory.SCOPE_SINGLETON,proxyMode = ScopedProxyMode.TARGET_CLASS)
    public class MyMath implements Calc{
    
       public Integer add(int num1,int num2){
            return num1+num2;
        }
    }
    @Configuration @ComponentScan(
    "com.yang.xiao.hui.aop") public class App { public static void main( String[] args ) { ApplicationContext ctx = new AnnotationConfigApplicationContext(App.class); MyMath myMath = (MyMath)ctx.getBean("myMath"); System.out.println(myMath.getClass()); System.out.println(ctx.getBean("scopedTarget.myMath").getClass()); } }

    启动main方法:

    二.源码分析,先看Scope注解:

     scope注解的proxyMode的属性决定了被该注解标注的类是否会被代理,这是一个枚举,有如下几个值:

     本次测试代码使用的是cglib代理,被Scope标注的对象,如果代理模式是jdk或者cglib代理的话,会在spring容器中产生2个bean,一个是代理的bean,一个是原始的bean,原始的bean的beanName被命名为:scopedTarget.xx:

    debug调试:

     

     省略n步:

     我们在这个方法里面可以看到spring是如何解析主启动类,扫描到其他的bean的:

    protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
                throws IOException {
    
            if (configClass.getMetadata().isAnnotated(Component.class.getName())) { //解析Component注解
                // Recursively process any member (nested) classes first
                processMemberClasses(configClass, sourceClass);
            }
    
            // Process any @PropertySource annotations
            for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
                    sourceClass.getMetadata(), PropertySources.class,
                    org.springframework.context.annotation.PropertySource.class)) {
                if (this.environment instanceof ConfigurableEnvironment) {
                    processPropertySource(propertySource);
                }
                else {
                    logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
                            "]. Reason: Environment must implement ConfigurableEnvironment");
                }
            }
    
            // Process any @ComponentScan annotations
            Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable( //解析Component注解ComponentScan.class
                    sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
            if (!componentScans.isEmpty() &&
                    !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
                for (AnnotationAttributes componentScan : componentScans) {
                    // The config class is annotated with @ComponentScan -> perform the scan immediately
                    Set<BeanDefinitionHolder> scannedBeanDefinitions =
                            this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName()); //componentScan解析器,对该注解进行解析
                    // Check the set of scanned definitions for any further config classes and parse recursively if needed
                    for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
                        BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
                        if (bdCand == null) {
                            bdCand = holder.getBeanDefinition();
                        }
                        if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
                            parse(bdCand.getBeanClassName(), holder.getBeanName());
                        }
                    }
                }
            }
    

    //..............................省略部分代码
    }

     

     

    protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
            Assert.notEmpty(basePackages, "At least one base package must be specified");
            Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
            for (String basePackage : basePackages) {
                Set<BeanDefinition> candidates = findCandidateComponents(basePackage);//通过包名,扫描该包名下的所有bean的定义信息
                for (BeanDefinition candidate : candidates) {
                    ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate); //scope注解解析器,获取Scope注解的属性信息,封装成ScopeMetadata 
                    candidate.setScope(scopeMetadata.getScopeName());
                    String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);//beanName生成器,这里是myMath
                    if (candidate instanceof AbstractBeanDefinition) {
                        postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
                    }
                    if (candidate instanceof AnnotatedBeanDefinition) {
                        AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
                    }
                    if (checkCandidate(beanName, candidate)) {
                        BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
                        definitionHolder =
                                AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); //这里处理scope注解,下面跟进这个
                        beanDefinitions.add(definitionHolder);
                        registerBeanDefinition(definitionHolder, this.registry);
                    }
                }
            }
            return beanDefinitions;
        }

    public static BeanDefinitionHolder createScopedProxy(BeanDefinitionHolder definition,
                BeanDefinitionRegistry registry, boolean proxyTargetClass) {
    
            String originalBeanName = definition.getBeanName();//原始的beanName: myMath
            BeanDefinition targetDefinition = definition.getBeanDefinition(); //原始的bean定义信息
            String targetBeanName = getTargetBeanName(originalBeanName); //scopedTarget.myMath
    
            // Create a scoped proxy definition for the original bean name,
            // "hiding" the target bean in an internal target definition.
            RootBeanDefinition proxyDefinition = new RootBeanDefinition(ScopedProxyFactoryBean.class); //创建一个代理对象
            proxyDefinition.setDecoratedDefinition(new BeanDefinitionHolder(targetDefinition, targetBeanName)); //将原始的bean定义信息作为被装饰的bean定义信息
            proxyDefinition.setOriginatingBeanDefinition(targetDefinition);//设置原始的bean定义信息
            proxyDefinition.setSource(definition.getSource());
            proxyDefinition.setRole(targetDefinition.getRole());
    
            proxyDefinition.getPropertyValues().add("targetBeanName", targetBeanName); 
            if (proxyTargetClass) {
                targetDefinition.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
                // ScopedProxyFactoryBean's "proxyTargetClass" default is TRUE, so we don't need to set it explicitly here.
            }
            else {
                proxyDefinition.getPropertyValues().add("proxyTargetClass", Boolean.FALSE);
            }
    
            // Copy autowire settings from original bean definition.
            proxyDefinition.setAutowireCandidate(targetDefinition.isAutowireCandidate());
            proxyDefinition.setPrimary(targetDefinition.isPrimary());
            if (targetDefinition instanceof AbstractBeanDefinition) {
                proxyDefinition.copyQualifiersFrom((AbstractBeanDefinition) targetDefinition);
            }
    
            // The target bean should be ignored in favor of the scoped proxy.
            targetDefinition.setAutowireCandidate(false);
            targetDefinition.setPrimary(false);
    
            // Register the target bean as separate bean in the factory.
            registry.registerBeanDefinition(targetBeanName, targetDefinition);//这里将原始的bean定义信息注册到了spring容器,而bean的名称是scopedTarget.myMath
    
            // Return the scoped proxy definition as primary bean definition
            // (potentially an inner bean).
            return new BeanDefinitionHolder(proxyDefinition, originalBeanName, definition.getAliases()); //这里将代理bean定义信息返回,bean的名称是原始的beanName,myMath,该beanHodler返回去后,会被注册到spring
        }

     总结:
    一个被Scope注解标注的类,如果scope的proxyMode不是no 或者defualt,那么会在spring创建2个bean,一个是代理bean,类型为ScopedProxyFactoryBean.class,一个是原始的bean:

    这里我们的MyMath类,生成了2个beanDefinition,一个是代理的beanDefinition,beanName为myMath,一个是原始的beanDefinition,beanName为scopedTarget.myMath;

    下面我们要分析ScopedProxyFactoryBean的创建过程了,我们知道XXFactoryBean会有一个getObject()方法返回XX代理对象:先看ScopedProxyFactoryBean继承体系

     

     通过继承图,我们知道,ScopedProxyFactoryBean实现了BeanFactoryAware接口,因此在ScopedProxyFactoryBean的创建过程中,会回调setBeanFactory(BeanFactory beanFactory),所以我们debug在该方法:

     我们详细看看该方法:

    @Override
        public void setBeanFactory(BeanFactory beanFactory) {
            if (!(beanFactory instanceof ConfigurableBeanFactory)) {
                throw new IllegalStateException("Not running in a ConfigurableBeanFactory: " + beanFactory);
            }
            ConfigurableBeanFactory cbf = (ConfigurableBeanFactory) beanFactory;
    
            this.scopedTargetSource.setBeanFactory(beanFactory);
    
            ProxyFactory pf = new ProxyFactory(); //创建代理工厂
            pf.copyFrom(this);
            pf.setTargetSource(this.scopedTargetSource);
    
            Assert.notNull(this.targetBeanName, "Property 'targetBeanName' is required");
            Class<?> beanType = beanFactory.getType(this.targetBeanName);//获取被代理类
            if (beanType == null) {
                throw new IllegalStateException("Cannot create scoped proxy for bean '" + this.targetBeanName +
                        "': Target type could not be determined at the time of proxy creation.");
            }
            if (!isProxyTargetClass() || beanType.isInterface() || Modifier.isPrivate(beanType.getModifiers())) {
                pf.setInterfaces(ClassUtils.getAllInterfacesForClass(beanType, cbf.getBeanClassLoader())); //获取被代理类的所有实现的接口
            }
    
            // Add an introduction that implements only the methods on ScopedObject.
            ScopedObject scopedObject = new DefaultScopedObject(cbf, this.scopedTargetSource.getTargetBeanName());
            pf.addAdvice(new DelegatingIntroductionInterceptor(scopedObject));//这里添加了一个增强器,在执行目标方法时,会拦截
    
            // Add the AopInfrastructureBean marker to indicate that the scoped proxy
            // itself is not subject to auto-proxying! Only its target bean is.
            pf.addInterface(AopInfrastructureBean.class);
    
            this.proxy = pf.getProxy(cbf.getBeanClassLoader());//创建代理对象
        }

     创建代理对象过程,跟之前aop源码分析一和源码分析二的时侯分析的一样了,这里不重复了





  • 相关阅读:
    Enterprise Solution 界面设计规范
    大型.NET商业软件代码保护技术 技术与实践相结合保护辛苦创造的劳动成果
    开源WinForms界面开发框架Management Studio 选项卡文档 插件 Office 2007蓝色风格 后台线程
    解析Visual Studio 2015促进生产力的10个新功能
    LLBL Gen Pro 4.2 Lite 免费的对象关系映射开发框架与工具
    Windows Server 2012部署Enterprise Solution 5.4
    ASP.NET MVC:some benefits of asp.net mvc
    Python:Opening Python Classes
    ASP.NET MVC:4 Ways To Prevent Duplicate Form Submission(转载)
    架构:The Onion Architecture : part 3(洋葱架构:第三篇)(转载)
  • 原文地址:https://www.cnblogs.com/yangxiaohui227/p/13403082.html
Copyright © 2011-2022 走看看