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.
  • 相关阅读:
    new SqlSessionFactoryBuilder().build(inputStream, properties)
    PooledDataSource--mybatis-3-mybatis-3.2.3
    MySQL 日期时间 专题
    使用httpclient抓取时,netstat 发现很多time_wait连接
    ajax提交整个form表单
    jquery 提交数据
    用form表单实现Ajax---post提交
    HTML 5 的data-* 自定义属性
    jquery序列化form表单使用ajax提交后处理返回的json数据
    jquery实现ajax提交form表单的方法总结
  • 原文地址:https://www.cnblogs.com/jssj/p/12373275.html
Copyright © 2011-2022 走看看