zoukankan      html  css  js  c++  java
  • spring源码阅读(一)-附录例子

    说明

    这里定义在源码中看到的各个接口使用例子

    BeanFactoryPostProcessor

    1.在bean创建加载为beanDefinition之后 初始化之前执行,我们可以通过改变beanDefinition或者动态注入

    /**
     * @author liqiang
     * @date 2020/10/23 17:53
     * @Description: (what)实现动态注册Car 可以通过配置XML或者注解 注入到Spring
     * (why)
     * (how)
     */
    public class AutoConfigBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
        @Override
        public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
            RootBeanDefinition beanDefinition=new RootBeanDefinition();
            beanDefinition.setBeanClass(Car.class);
            beanDefinition.setBeanClassName("org.springframework.lq.beanFactory.Car");
            BeanDefinitionHolder beanDefinitionHolder=new BeanDefinitionHolder(beanDefinition,"car");
            // 我们把这步叫做 注册Bean 实现了BeanDefinitionRegistry接口
            //参考:org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#processBeanDefinition
            BeanDefinitionReaderUtils.registerBeanDefinition(beanDefinitionHolder, (BeanDefinitionRegistry) beanFactory);
        }
    }

    BeanPostProcessor

    * 1.实例化、依赖注入完毕,在调用显示的初始化之前完成一些定制任务
    * 2.实例化、依赖注入、初始化完毕时执行,完成一些定制任务

    可以通过此扩展完成实现代理 或者动态改变属性值

    如:以下例子友好的封装实现MQ监听器

    1.定义接口

    public interface RabbitMQListener<T> {
        String getQueueName();
        String getRoutingKey();
        String getExchangeName();
        void process(T t);
    }

    2.自动监听实现

    /**
    *通过xml或者注解的方式注册到spring即可
    **/
    public
    class AutoRegisterRabbitMQListener implements BeanPostProcessor { @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { //是否是监听器 if(bean instanceof RabbitMQListener){ RabbitMQListener rabbitMQListener=(RabbitMQListener)bean; //=================动态监听=============================== String exchangeName = rabbitMQListener.getExchangeName(); String queueName = rabbitMQListener.getQueueName(); String routingKey =rabbitMQListener.getRoutingKey(); Connection connection = newConnection(); //声明一个channel一个连接可以监听多个channel 连接复用 Channel channel = connection.createChannel(); //声明一个名字为test 非自动删除的 direct类型的exchange 更多配置书37页 channel.exchangeDeclare(exchangeName, "direct", true); //声明一个持久化,非排他,非自动删除的队列 channel.queueDeclare(queueName, true, false, false, null); //将队列与交换器绑定 channel.queueBind(queueName, exchangeName, routingKey); //未名字路由的回调 channel.addReturnListener(new ReturnListener() { @Override public void handleReturn(int replyCode, String replyText, String exchange, String routingKey, AMQP.BasicProperties properties, byte[] body) throws IOException { //反射获取当前RabbitMQListener的泛型classs Class resultType=getMessageClass(); rabbitMQListener.process(JSON.parseObject(new String(body),resultType)); } }); } return bean; } }

    3.当需要实现一个监听学生的消费者

    public class AddStudentListener implements RabbitMQListener<Student> {
        @Override
        public String getQueueName() {
            return "testQueue";
        }
    
        @Override
        public String getRoutingKey() {
            return "testRotingkey";
        }
    
        @Override
        public String getExchangeName() {
            return "testExchange";
        }
    
        @Override
        public void process(Student student) {
            System.out.println("student开始消费了");
        }
    }

    FactoryBean

    用于一些复杂对象的创建 比如创建对象过程中要做很多复杂逻辑

    xml方式

    1.定义CarFactoryBean

    public class CarFactoryBean implements FactoryBean<Car> {
        /**
         * 颜色
         */
        private String color;
        /*
         *品牌
         */
        private String brand;
        /**
         * 价格
         */
        private double price;
        /**
         * 销售区域
         */
        private String area;
        @Override
        public Car getObject() throws Exception {
            Car car=new Car();
            car.setPrice(price);
            car.setBrand(brand);
            car.setArea(area);
            if(area.equals("中国")){
                car.setPrice(price*0.9);
            } else if (area.equals("美国")) {
                car.setPrice(price*0.8);
            }
            return  car;
        }
    
    
        @Override
        public Class<?> getObjectType() {
            return Car.class;
        }
    }

    2.xml配置

    <bean class = "org.springframework.lq.factorybean.CarFactoryBean" id = "car">
            <property name = "color" value ="红色"/>
            <property name = "brand" value ="滴滴"/>
            <property name = "price" value ="12"/>
            <property name = "area" value ="中国"/>
        </bean>

    注解方式

    @Configuration
    public class CarFactoryBeanConfig {
        @Bean(name = "car")
        public Car createCar(){
            Car car=new Car();
            car.setPrice(12);
            car.setBrand("滴滴");
            car.setArea("中国");
            car.setPrice(car.getPrice()*0.9);
            return  car;
        }
    }

    工厂模式生成 Bean

    静态工厂

    <bean id="clientService"
        class="examples.ClientService"
        factory-method="createInstance"/>
    public class ClientService {
        private static ClientService clientService = new ClientService();
        private ClientService() {}
    
        // 静态方法
        public static ClientService createInstance() {
            return clientService;
        }
    }

    实例工厂

    <bean id="serviceLocator" class="examples.DefaultServiceLocator">
        <!-- inject any dependencies required by this locator bean -->
    </bean>
    
    <bean id="clientService"
        factory-bean="serviceLocator"
        factory-method="createClientServiceInstance"/>
    
    <bean id="accountService"
        factory-bean="serviceLocator"
        factory-method="createAccountServiceInstance"/>
    public class DefaultServiceLocator {
    
        private static ClientService clientService = new ClientServiceImpl();
    
        private static AccountService accountService = new AccountServiceImpl();
    
        public ClientService createClientServiceInstance() {
            return clientService;
        }
    
        public AccountService createAccountServiceInstance() {
            return accountService;
        }
    }

    ApplicationListener

    如果定义了线程池则通过线程池异步发送。否则同步发送

        </bean>
        <!-- 定义一个固定大小的线程,采用factory-method和静态方法的形式,参数注入使用构造函数注入 -->
        <bean name="executor" class="java.util.concurrent.Executors" factory-method="newFixedThreadPool">
                <constructor-arg index="0"><value>5</value></constructor-arg>
        </bean>
        <!-- 定义applicationEventMulticaster,注入线程池和errorHandler,此处使用系统自带的广播器,也可以注入其他广播器, -->
        <bean name="applicationEventMulticaster" class="org.springframework.context.event.SimpleApplicationEventMulticaster">
            <property name="taskExecutor" ref="executor"></property>
            <property name="errorHandler" ref="errorHandler"></property>
        </bean>
        <!-- 定义一个errorHandler,统一处理异常信息 实现ErrorHandler接口-->
        <bean name="errorHandler" class="com.zjl.MyErrorHandler"></bean>

    1.定义Event

    public class StudentEvent extends ApplicationEvent {
        /**
         * Create a new ApplicationEvent.
         *
         * @param source the object on which the event initially occurred (never {@code null})
         */
        public StudentEvent(Object source) {
            super(source);
        }
    }

    2.定义监听器

    /**
    *通过注解或者xml配置初始化
    **/
    public
    class SpringAddStudentListener implements ApplicationListener<StudentEvent> { /** * Handle an application event. * * @param event the event to respond to */ @Override public void onApplicationEvent(StudentEvent event) { System.out.println("收到消息..."); System.out.println((Student)event.getSource()); } }

    3.发送消息

    ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(
                    new String[] {LQCONTEXT}, getClass());
            ctx.publishEvent(new StudentEvent(new Student()));

    lookup-method

    通过代理返回指定bean

    1.java

    public abstract class AbstractStudentFactory
    {
     public abstract Student createStudent();
    }

    2.xml配置

        <bean name="abstractStudentFactory"  class="org.springframework.lq.lookup.AbstractStudentFactory">
    <!--返回id为student的bean--> <lookup-method name="createStudent" bean="student"/> </bean>

    3.使用

        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(
                    new String[] {LQCONTEXT}, getClass());
            AbstractStudentFactory abstractStudentFactory=ctx.getBean(AbstractStudentFactory.class);
             Student student=abstractStudentFactory.createStudent();

    replaced-method

    替换bean的方法

    1.定义java类

    public class Source {
        public void load(){
            System.out.println("我是sourceLoad方法");
        }
    }

    2.定义替换类

    ublic class SourceMethodReplace implements org.springframework.beans.factory.support.MethodReplacer {
        /**
         * Reimplement the given method.
         *
         * @param obj    the instance we're reimplementing the method for
         * @param method the method to reimplement
         * @param args   arguments to the method
         * @return return value for the method
         */
        @Override
        public Object reimplement(Object obj, Method method, Object[] args) throws Throwable {
            System.out.println("我是替换方法");
            return null;
        }
    }

    3.定义xml

    <bean name="source"  class="org.springframework.lq.replacedmethod.Source">
            <!-- 定义 load 这个方法要被替换掉 -->
            <replaced-method name="load" replacer="sourceMethodReplace"/>
        </bean>
        <bean name="sourceMethodReplace"  class="org.springframework.lq.replacedmethod.SourceMethodReplace"></bean>

    4.测试

    ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(
    				new String[] {LQCONTEXT}, getClass());
    
    		Source source=ctx.getBean(Source.class);
    		source.load();  

    ConversionService

    最有用的场景就是,它用来将前端传过来的参数和后端的 controller 方法上的参数进行绑定的时候用。

    像前端传过来的字符串、整数要转换为后端的 String、Integer 很容易,但是如果 controller 方法需要的是一个枚举值,或者是 Date 这些非基础类型(含基础类型包装类)值的时候,我们就可以考虑采用 ConversionService 来进行转换。

    <bean id="conversionService"
      class="org.springframework.context.support.ConversionServiceFactoryBean">
      <property name="converters">
        <list>
          <bean class="com.javadoop.learning.utils.StringToEnumConverterFactory"/>
        </list>
      </property>
    </bean>
    public class StringToDateConverter implements Converter<String, Date> {
    
        @Override
        public Date convert(String source) {
            try {
                return DateUtils.parseDate(source, "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "HH:mm:ss", "HH:mm");
            } catch (ParseException e) {
                return null;
            }
        }
    }
  • 相关阅读:
    关于JSON可能出现的错误,待更/todo
    mongoose的安装与使用(书签记录) 2017
    HTTP的学习记录3--HTTPS和HTTP
    HTTP的学习记录(二)头部
    HTTP(一)概述
    LeetCode 455. Assign Cookies
    LeetCode 453. Minimum Moves to Equal Array Elements
    LeetCode 448. Find All Numbers Disappeared in an Array
    LeetCode 447. Number of Boomerangs
    LeetCode 416. Partition Equal Subset Sum
  • 原文地址:https://www.cnblogs.com/LQBlog/p/13878553.html
Copyright © 2011-2022 走看看