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();

  

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章