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,此处使用系统自带的广播器,也可以注入其他广播器,如果通过applicationContext发送beanName
 必须为applicationEventMuticaster 源码初始化就是通过这个name 不建议覆盖 因为可能影响 其他jar包的默认使用-->
    <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;
        }
    }
}

Condition注解

说明

条件判断,是否注入当前bean

接口实现

当windows系统才注入当前bean

public class WindowsCondition implements Condition {
 
    /**
     * @param conditionContext:判断条件能使用的上下文环境
     * @param annotatedTypeMetadata:注解所在位置的注释信息
     * */
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        //获取ioc使用的beanFactory
        ConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory();
        //获取类加载器
        ClassLoader classLoader = conditionContext.getClassLoader();
        //获取当前环境信息
        Environment environment = conditionContext.getEnvironment();
        //获取bean定义的注册类
        BeanDefinitionRegistry registry = conditionContext.getRegistry();
 
        //获得当前系统名
        String property = environment.getProperty("os.name");
        //包含Windows则说明是windows系统,返回true
        if (property.contains("Windows")){
            return true;
        }
        return false;
    }
}

标识在类上

只有windowsCondition满足条件 容易才会初始化这个类

@Conditional({WindowsCondition.class})
@Configuration
public class BeanConfig {
 
    @Bean(name = "bill")
    public Person person1(){
        return new Person("Bill Gates",62);
    }
 
    @Bean("linus")
    public Person person2(){
        return new Person("Linus",48);
    }
}

标志在方法上

@Configuration
public class BeanConfig {
 
    //只有一个类时,大括号可以省略
    //如果WindowsCondition的实现方法返回true,则注入这个bean    
    @Conditional({WindowsCondition.class})
    @Bean(name = "bill")
    public Person person1(){
        return new Person("Bill Gates",62);
    }
 
    //如果LinuxCondition的实现方法返回true,则注入这个bean
    @Conditional({LinuxCondition.class})
    @Bean("linus")
    public Person person2(){
        return new Person("Linus",48);
    }
}

@DependOn

先初始化eventListener 才会初始化eventSource


@Configuration
@ComponentScan(basePackages = "dependsondemo")
public class SpringConfig {

    @Bean
    @DependsOn(value = {"eventListener"})
    public EventSource eventSource(){
        return new EventSource();
    }

    @Bean
    public EventTListener eventListener(){
        return new EventTListener();
    }
}

 

posted @ 2020-10-26 15:03  意犹未尽  阅读(238)  评论(0编辑  收藏  举报