• 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;
            }
        }
    }
  • 相关阅读:
    用C++读写EXCEL文件的几种方式比较
    20个值得收藏的网页设计开放课件
    char* 应用, 去除字符串内多余空格, 用算法而非库函数
    东拉西扯:王建硕主义
    Lisp 的本质(The Nature of Lisp)
    web前端:html
    [原译]理解并实现原型模式实现ICloneable接口.理解深浅拷贝
    [原译]理解并实现装饰器模式
    3分钟理解Lambda表达式
    [原译]实现IEnumerable接口&理解yield关键字
  • 原文地址:https://www.cnblogs.com/LQBlog/p/13878553.html
Copyright © 2020-2023  润新知