zoukankan      html  css  js  c++  java
  • 《Java Spring框架》扩展Spring案例(一)

    1.下载源码

        源码部署:https://www.cnblogs.com/jssj/p/11631881.html

        并不强求,最好是有源码(方便理解和查问题)。

    2. 创建子项目

        Spring项目中创建子项目:https://www.cnblogs.com/jssj/p/12329839.html

    3. 案例(两个干预Spring生成Bean)

    AppConfig:

    package accelerate.app;
    
    import org.springframework.context.annotation.ComponentScan;
            import org.springframework.context.annotation.Configuration;
    
    @Configuration
    @ComponentScan("accelerate")
    public class AppConfig {
    }

    Apple

    package accelerate.bean;
    
    import org.springframework.stereotype.Component;
    
    @Component
    public class Apple {
        public Apple(){
            System.out.println("Apple");
        }
    }

    Test

    package accelerate.bean;
    
    public class Test {
        public Test(){
            System.out.println("构造方法-Test");
        }
    }

    AccelerateBeanFactoryPostProcessor

    package accelerate.mybatis;
    
    import accelerate.bean.Test;
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
    import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
    import org.springframework.beans.factory.support.GenericBeanDefinition;
    import org.springframework.stereotype.Component;
    
    @Component
    public class AccelerateBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
            GenericBeanDefinition genericBeanDefinition = (GenericBeanDefinition)beanFactory.getBeanDefinition("apple");
            System.out.println("插手前:" + genericBeanDefinition.getBeanClassName());
            genericBeanDefinition.setBeanClass(Test.class);
        }
    }

    Demo

    package accelerate.test;
    
    import accelerate.app.AppConfig;
    import accelerate.bean.Test;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    
    public class Demo {
        public static void main(String[] args) {
            AnnotationConfigApplicationContext annotationConfigApplicationContext =
                    new AnnotationConfigApplicationContext(AppConfig.class);
    
            System.out.println("最终生成的Bean:"+ annotationConfigApplicationContext.getBean("apple"));
        }
    }

    build.gradle 

    group 'org.springframework'
    version '3.2.19.BUILD-SNAPSHOT'
    
    apply plugin: 'java'
    
    sourceCompatibility = 1.8
    
    repositories {
        mavenCentral()
    }
    
    dependencies {
        testCompile group: 'junit', name: 'junit', version: '4.12'
        compile project(':spring-context')
        compile project(':spring-beans')
    
    }

    运行结果:

    结论: Apple类加了注解@Compnent而Test类没有加注解,最后通过getBean(Test.class)却拿到了Apple这个Bean对象。

    根据调试:看到Spring源码AbstractApplicationContext 类有如下代码循环调用。

       /**
         * author hubt
         * 该代码执行循环执行实现BeanFactoryPostProcessor的类的方法。
         * @param postProcessors
         * @param beanFactory
         */
        private void invokeBeanFactoryPostProcessors(
                Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) {
    
            for (BeanFactoryPostProcessor postProcessor : postProcessors) {
                postProcessor.postProcessBeanFactory(beanFactory);
            }
        }

    如何修改干预Spring生成Bean的过程。

    /**
         * author
         * Spring会将Bean的信息(类名,修饰符等等)写入BeanDefinition类中,并将这些BeanDefinition存放入beanDefinitionMap中。
         * 该方法是根据你定义的名称获取对应存放bean信息的BeanDefinition。
         * @param beanName name of the bean to find a definition for
         * @return
         * @throws NoSuchBeanDefinitionException
         */
        @Override
        public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
            BeanDefinition bd = this.beanDefinitionMap.get(beanName);
            if (bd == null) {
                if (this.logger.isTraceEnabled()) {
                    this.logger.trace("No bean named '" + beanName + "' found in " + this);
                }
                throw new NoSuchBeanDefinitionException(beanName);
            }
            return bd;
        }

    案例二:

    AppConfig

    package accelerate.app;
    
    import org.springframework.context.annotation.ComponentScan;
            import org.springframework.context.annotation.Configuration;
    
    @Configuration
    @ComponentScan("accelerate")
    public class AppConfig {
    }

    AopTest

    package accelerate.mybatis;
    
    import accelerate.service.AccelerateInvocationHandler;
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.config.BeanPostProcessor;
    import org.springframework.stereotype.Component;
    
    import java.lang.reflect.Proxy;
    
    @Component
    public class AopTest implements BeanPostProcessor {
    
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            return bean;
        }
    
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            if(beanName.equals("cityService")){
                Class<?> aClass = bean.getClass().getInterfaces()[0];
                Class[] classes = new Class[]{aClass};
                Object o = Proxy.newProxyInstance(AopTest.class.getClassLoader(), classes, new AccelerateInvocationHandler(bean));
                return o;
            }
            return bean;
        }
    }

    AccelerateInvocationHandler

    package accelerate.service;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    
    public class AccelerateInvocationHandler implements InvocationHandler {
    
        Object o;
    
        public AccelerateInvocationHandler(Object o){
            this.o = o;
        }
    
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("aop----before");
            Object result = method.invoke(o);
            System.out.println("aop----after");
            return result;
        }
    }

    CityService

    package accelerate.service;
    
    import org.springframework.stereotype.Component;
    
    @Component("cityService")
    public class CityService implements L {
    
        public CityService(){
            System.out.println("构造方法----CityService");
        }
    
        public void query() {
            System.out.println("logic---db");
        }
    }
    package accelerate.service;
    
    public interface L {
        public void query();
    }

    Demo

    package accelerate.test;
    
    import accelerate.app.AppConfig;
    import accelerate.service.L;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    
    public class Demo {
        public static void main(String[] args) {
            AnnotationConfigApplicationContext annotationConfigApplicationContext =
                    new AnnotationConfigApplicationContext(AppConfig.class);
    
            L bean = annotationConfigApplicationContext.getBean(L.class);
            bean.query();
        }
    }

    build.gradle   配置不变。

    运行结果:

    结论:原本CityService只是一个普通Bean,被修改成一个代理类。

    源码分析如下:

        /**
         * author hubt
         * 循环执行Spring的后置处理,也就是说实现或者继承BeanPostProcessors的类都会在这里被运用到
         * @param existingBean the new bean instance
         * @param beanName the name of the bean
         * @return
         * @throws BeansException
         */
        public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
                throws BeansException {
    
            Object result = existingBean;
            for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
                result = beanProcessor.postProcessAfterInitialization(result, beanName);
                if (result == null) {
                    return result;
                }
            }
            return result;
        }

    这边还运用了Java动态代理:https://www.cnblogs.com/jssj/p/11771408.html

    案例三:

    package accelerate1.app;
    
    import org.springframework.context.annotation.ComponentScan;
            import org.springframework.context.annotation.Configuration;
    
    @Configuration
    @ComponentScan("accelerate1")
    public class AppConfig {
    }
    package accelerate1.mybatis;
    
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
    import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
    import org.springframework.beans.factory.support.GenericBeanDefinition;
    import org.springframework.stereotype.Component;
    
    @Component
    public class AccelerateBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
            GenericBeanDefinition genericBeanDefinition = (GenericBeanDefinition)beanFactory.getBeanDefinition("cityService");
            /***将CityService,设置成自动装配的(Autowired的bytype方式)***/
            genericBeanDefinition.setAutowireMode(2);
        }
    }
    package accelerate1.service;
    
    import org.springframework.stereotype.Component;
    
    @Component("cityService")
    public class CityService{
    
        Province province;
    
        public void setProvince(Province province) {
            this.province = province;
        }
    
        public void query() {
            System.out.println(province);
        }
    }
    package accelerate1.service;
    
    import org.springframework.stereotype.Component;
    
    @Component
    public class Province {
    
        public  Province(){
            System.out.println("init province");
        }
    }
    package accelerate1.test;
    
    import accelerate1.app.AppConfig;
    import accelerate1.service.CityService;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    
    public class Demo1 {
        public static void main(String[] args) {
            AnnotationConfigApplicationContext annotationConfigApplicationContext =
                    new AnnotationConfigApplicationContext(AppConfig.class);
            annotationConfigApplicationContext.getBean(CityService.class).query();
        }
    }

    运行结果:

    可以看到:打印了Province这个对象的信息,我们没有使用@Autowired注解进行注入,而是通过后置处理器将AutowiredMode的值修改点而进行自动注入。

    AutowiredMode的值有4种:

    1. no:   不注入(默认)。

    2. byname: 按属性名称自动连接。Spring寻找与需要自动装配的属性同名的bean。

    3. bytype:  如果容器中恰好存在一个属性类型的bean,则使该属性自动连接。如果存在多个错误,则会引发致命异常

    4. constructor:类似于byType但适用于构造函数参数。如果容器中不存在构造函数参数类型的一个bean,则将引发致命错误

    注意:自动注入需要存在构造函数或者set方法才可以注入;而@Autowired不需要set方法,缺点:@Autowired只能注解在单个引用上。

    Spring IOC 原理图:

     感谢观看。

    This moment will nap, you will have a dream; But this moment study,you will interpret a dream.
  • 相关阅读:
    什么样的代码称得上是好代码?
    九年程序人生 总结分享
    Docker入门 第一课 --.Net Core 使用Docker全程记录
    阿里云 Windows Server 2012 r2 部署asp.net mvc网站 平坑之旅
    Visual studio 2015 Community 安装过程中遇到问题的终极解决
    Activiti6.0 spring5 工作流引擎 java SSM流程审批 项目框架
    java 进销存 库存管理 销售报表 商户管理 springmvc SSM crm 项目
    Leetcode名企之路
    24. 两两交换链表中的节点
    21. 合并两个有序链表
  • 原文地址:https://www.cnblogs.com/jssj/p/12373275.html
Copyright © 2011-2022 走看看