說明
這裏定義在源碼中看到的各個接口使用例子
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();