说明
这里定义在源码中看到的各个接口使用例子
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; } } }