zoukankan      html  css  js  c++  java
  • [Js-Spring]Bean的装配

    Bean 的装配

    Bean 的装配:即 Bean 对象的创建。容器根据代码要求创建 Bean 对象后再传递给代码的过程中,称为 Bean 的装配

    Spring 的默认装配方式是容器首先调用 Bean 类的无参构造器,创建空值的实例对象

    <bean id="someService" class="com.neu.ba01.SomeServiceImpl"></bean>

    动态工厂 Bean

    有时候项目可能需要通过工厂类来创建 Bean 实例,这时候我们有两种方案

    一种是,只配置(创建)一个 Factory 工厂 Bean,在代码中调用 factory 的 getXxx() 方法获取所需要的对象实例,显然这种做法使得耦合度太高(代码里面都写死了调用什么方法)

    另一种是(推荐),使用 Spring 的动态工厂 Bean ,factory-bean 指定的是相应的工厂 Bean,factory-method 指定创建所用方法,这时我们至少要定义两个 Bean ,工厂类 Bean,与所要创建的目标类 Bean

    <!-- 动态工厂Bean -->
    <bean id="serviceFactory" class="com.neu.ba02.ServiceFactory"></bean>
    <!-- 目标Bean -->
    <bean id="someService" factory-bean="serviceFactory" factory-method="getService"></bean>

    代码中直接获取 someService 的 Bean 即可

    ISomeService service = (ISomeService) ac.getBean("someService");

    静态工厂 Bean

    因为静态工厂是通过调用工厂类的静态方法来创建实例的,所以不需要工厂对象,所以直接在配置文件中配置目标类 Bean 即可,当然工厂类 class 和工厂方法 factory-method 要配置

    <!-- 静态态工厂Bean -->
    <bean id="someService" class="com.neu.ba03.ServiceFactory" factory-method="getService"></bean>

    容器中 Bean 的作用域

    • singleton:单态模式。在整个容器中,使用 singleton 定义的 Bean 将会是单例的,只有一个实例
    • prototype:原型模式。每次调用 getBean() 方法都是一个新的实例
    • request:每次 HTTP 请求,都会产生一个不同的 Bean 实例
    • session:对于每个不同的 HTTP session,都将产生一个不同的 Bean 的实例

    注:

    scope 为 singleton 的 Bean 对象,在容器被创建时即装配好了,这是 Bean 的默认 scope 值

    scope 为 protoscope 的 Bean 对象,Bean 实例在使用该 Bean 实例的时候才会被创建

    Bean 后处理器

    Bean 后处理器是一种特殊的 Bean,容器中所有的 Bean 在初始化的时候,均会执行此类的两个方法。代码中需要自定义后处理器,实现 BeanPostProcessor 接口,该接口中包含两个方法,分别在目标 Bean 初始化完毕之前与之后执行,它们的返回值是:功能被扩展或增强后的Bean对象

    在配置文件中配置 Bean 

    <bean class="com.neu.ba05.MyBeanPostProcessor"></bean>

    自定义 BeanPostProcessor

    package com.neu.ba05;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.config.BeanPostProcessor;
    
    public class MyBeanPostProcessor implements BeanPostProcessor {
    
        public MyBeanPostProcessor() {
            super();
            System.out.println("初始化MyBeanPostProcessor对象");
        }
    
        // bean:当前调用执行Bean后处理器的Bean对象
        // beanName:当前调用执行Bean后处理器的Bean对象的ID
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            System.out.println("执行MyBeanPostProcessor的postProcessBeforeInitialization()方法");
            return bean;
        }
    
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            System.out.println("执行MyBeanPostProcessor的postProcessAfterInitialization()方法");
            Object proxy = null;
            if ("someService1".equals(beanName)) {
                proxy = Proxy.newProxyInstance(bean.getClass().getClassLoader(), bean.getClass().getInterfaces(),
                        new InvocationHandler() {
    
                            @Override
                            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                                Object result = method.invoke(bean, args);
                                if (result != null) {
                                    result = ((String) result).toUpperCase();
                                }
                                return result;
                            }
                        });
                return proxy;
            }
            return bean;
        }
    
    }

    观察上面代码,不说也很容易推测出 beanName 是我们获取到的 Bean 实例的名字,bean 是我们获取到的 Bean 实例,返回的是通过 JDK 动态代理得到的强化过的 Bean 实例

    定制 Bean 的生命始末

    可以为 Bean 定制初始化后的生命行为,也可以为 Bean 定制销毁前的生命行为。

    定制的流程为首先这些方法在 Bean 类中事先定义好(方法名随意的 public void 方法),然后在 Bean 标签中添加如下属性,

    init-method:指定初始化方法的方法名

    destroy-method:指定销毁方法的方法名

    注:

    若想看到结果,需要

    1)Bean 为 singleton 

    2)要确保容器关闭,接口 ApplicationContext 没有 close() 方法,但其实现类有。所以,可以将 ApplicationContext 强转为实现类对象关闭

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="
            http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <!-- bean definitions here -->
        <bean id="someService" class="com.neu.ba06.SomeServiceImpl"
            init-method="initAfter" destroy-method="preDestory"></bean>
    
    </beans>
    package com.neu.ba06;
    
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class MyTest {
    
        @Test
        public void test01() {
            // 加载Spring配置文件,创建Spring容器对象
            String resource = "com/neu/ba06/applicationContext.xml";
            ApplicationContext ac = new ClassPathXmlApplicationContext(resource);
            // 从容器中获取指定的Bean对象
            ISomeService service = (ISomeService) ac.getBean("someService");
            service.doFirst();
            service.doSecond();
            // 销毁方法执行有两个要求:
            // 1)被销毁的对象需要是singleton的,即单例的
            // 2)容器需要显式关闭
            ((ClassPathXmlApplicationContext) ac).close();
        }
    }

    Bean 的生命周期

    Bean 实例从创建到最后阶段经过很多过程,执行很多生命周期方法

    Step1:调用无参构造函数,创建实例对象

    Step2:调用参数的 setter,为属性注入值

    Step3:若 Bean 实现了 BeanNameAware 接口,则会执行接口方法 setBeanName(String beanId),使 Bean 类可以获得其在容器中的 id 名称

    Step4:若 Bean 实现了 BeanFactoryAware 接口,则会执行接口方法 setBeanFactory(BeanFactory factory),使 Bean 类可以获取到 BeanFactory 对象

    Step5:若定义并注册了 Bean 后处理器 BeanPostProcessor,则执行接口方法 postProcessBeforeInitialization()

    Step6:若 Bean 实现了 InitializingBean 接口,则执行接口方法 afterPropertiesSet(),该方法在 Bean 的所有属性的 set 方法执行完毕之后执行,标志着 Bean 初始化结束

    Step7:若设置了init-method 方法,则执行

    Step8:若定义并注册了 Bean 后处理器 BeanPostProcessor,则执行接口方法 postProcessAfterInitialization()

    Step9:执行业务方法

    Step10:若 Bean 实现了 DisposableBean 接口,则执行接口方法 destroy()

    Step11:若设置了 destroy-method 方法,则执行

    ISomeService.java

    package com.neu.ba07;
    
    public interface ISomeService {
        public String doFirst();
    
        public void doSecond();
    }

    SomeServiceImpl.java

    package com.neu.ba07;
    
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.BeanFactory;
    import org.springframework.beans.factory.BeanFactoryAware;
    import org.springframework.beans.factory.BeanNameAware;
    import org.springframework.beans.factory.DisposableBean;
    import org.springframework.beans.factory.InitializingBean;
    
    public class SomeServiceImpl
            implements ISomeService, BeanNameAware, BeanFactoryAware, InitializingBean, DisposableBean {
        private String adao;
        private String bdao;
    
        public void setAdao(String adao) {
            System.out.println("Step2:执行setAdao()方法");
            this.adao = adao;
        }
    
        public void setBdao(String bdao) {
            System.out.println("Step2:执行setBdao()方法");
            this.bdao = bdao;
        }
    
        public SomeServiceImpl() {
            System.out.println("Step1:对象的创建");
        }
    
        @Override
        public String doFirst() {
            System.out.println("Step9:(执行主业务方法)执行doFirst()方法");
            return null;
        }
    
        @Override
        public void doSecond() {
            System.out.println("执行doSecond()方法");
        }
    
        public void initAfter() {
            System.out.println("Step7:--初始化之后--");
        }
    
        public void preDestory() {
            System.out.println("Ste11:---销毁之前---");
        }
    
        @Override
        public void setBeanName(String name) {
            System.out.println("Step3:beanName = " + name);
        }
    
        @Override
        public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
            System.out.println("Step4:获取到BeanFactory容器");
        }
    
        @Override
        public void afterPropertiesSet() throws Exception {
            System.out.println("Step6:当前Bean的初始化工作已经完毕");
        }
    
        @Override
        public void destroy() throws Exception {
            System.out.println("Step10:准备开始销毁工作,进行销毁流程");
        }
    
        @Override
        public String toString() {
            return "SomeServiceImpl [adao=" + adao + ", bdao=" + bdao + "]";
        }
    
    }

    MyBeanPostProcessor.java

    package com.neu.ba07;
    
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.config.BeanPostProcessor;
    
    public class MyBeanPostProcessor implements BeanPostProcessor {
    
        // bean:当前调用执行Bean后处理器的Bean对象
        // beanName:当前调用执行Bean后处理器的Bean对象的ID
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            System.out.println("Step5:执行MyBeanPostProcessor的postProcessBeforeInitialization()方法");
            return bean;
        }
    
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            System.out.println("Step8:执行MyBeanPostProcessor的postProcessAfterInitialization()方法");
            
            return bean;
        }
    
    }

    applicationContext.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="
            http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <!-- bean definitions here -->
        <bean id="someService" class="com.neu.ba07.SomeServiceImpl" init-method="initAfter" destroy-method="preDestory">
            <property name="adao" value="AAA"></property>
            <property name="bdao" value="BBB"></property>
        </bean>
        <bean class="com.neu.ba07.MyBeanPostProcessor"></bean>
    
    </beans>

    MyTest.java

    package com.neu.ba07;
    
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class MyTest {
    
        @Test
        public void test01() {
            // 加载Spring配置文件,创建Spring容器对象
            String resource = "com/neu/ba07/applicationContext.xml";
            ApplicationContext ac = new ClassPathXmlApplicationContext(resource);
            // 从容器中获取指定的Bean对象
            ISomeService service = (ISomeService) ac.getBean("someService");
            service.doFirst();
    
            ((ClassPathXmlApplicationContext) ac).close();
        }
    }

    执行结果:(控制台输出)

    log4j:WARN No appenders could be found for logger (org.springframework.core.env.StandardEnvironment).
    log4j:WARN Please initialize the log4j system properly.
    Step1:对象的创建
    Step2:执行setAdao()方法
    Step2:执行setBdao()方法
    Step3:beanName = someService
    Step4:获取到BeanFactory容器
    Step5:执行MyBeanPostProcessor的postProcessBeforeInitialization()方法
    Step6:当前Bean的初始化工作已经完毕
    Step7:--初始化之后--
    Step8:执行MyBeanPostProcessor的postProcessAfterInitialization()方法
    Step9:(执行主业务方法)执行doFirst()方法
    Step10:准备开始销毁工作,进行销毁流程
    Ste11:---销毁之前---

    <bean/>标签的 id 属性与 name 属性

    一般情况下,命名<bean/>使用 id 属性,而不使用 name 属性。在没有 id 属性的情况下,name 属性与 id 属性的作用是相同的。但是当<bean/>中含有一些特殊字符的时候,就必须要使用 name 属性了。

    id 的命名必须要满足 XML 对 ID 的命名规范:必须以字幕开头,可以包含字母,数字,下划线,连字符,句号,冒号

    name 属性值则可以包含各种字符

  • 相关阅读:
    过滤器
    联系数据库 电话本例子
    连接数据库日志例题
    登录注册 servlet
    Pandas截取列部分字符,并据此修改另一列的数据
    Excel 如何判断某列哪些单元格包含某些字符
    Pandas逐行读取Dateframe并转为list
    Pandas: 使用str.replace() 进行文本清洗
    如何在xlwt中编写多个列的单元格?
    python:循环定义、赋值多个变量
  • 原文地址:https://www.cnblogs.com/jiasq/p/8598364.html
Copyright © 2011-2022 走看看