BeanFactory和它的对象注册和依赖绑定的三种方式

一、Spring中的BeanFactory是什么?

  BeanFactory是个基本的IoC容器,提供完整的IoC服务支持,负责对象创建的管理依赖注入服务

  如果没有特殊指定,默认采用延迟初始化策略(lazy-load)。只有当客户端对象需要访问容器中的某个受管对象的时候,才对该受管对象进行初始化以及依赖注入操作

public interface BeanFactory {
    String FACTORY_BEAN_PREFIX = "&";

    Object getBean(String var1) throws BeansException;

    <T> T getBean(String var1, Class<T> var2) throws BeansException;

    <T> T getBean(Class<T> var1) throws BeansException;

    Object getBean(String var1, Object... var2) throws BeansException;

    <T> T getBean(Class<T> var1, Object... var2) throws BeansException;

    boolean containsBean(String var1);

    boolean isSingleton(String var1) throws NoSuchBeanDefinitionException;

    boolean isPrototype(String var1) throws NoSuchBeanDefinitionException;

    boolean isTypeMatch(String var1, Class<?> var2) throws NoSuchBeanDefinitionException;

    Class<?> getType(String var1) throws NoSuchBeanDefinitionException;

    String[] getAliases(String var1);
}

二、BeanFactory的对象注册和依赖绑定的三种方式

1、直接编码方式(无需xml文件)

 1.1 项目结构

1.2 各个代码

public class App {
    private String says = "App";

    private App(){
        System.out.println("调用App无参构造");
    }

    public App(String says) {
        System.out.println("调用App有参构造, 参数says为:" + says);
        this.says = says;
    }

    public void say(){
        System.out.println("App.say():" + says);
    }

    public String getSays() {
        return says;
    }

    public void setSays(String says) {
        this.says = says;
    }

    @Override
    public String toString() {
        return "App{" +
                "says='" + says + '\'' +
                '}';
    }
}
public class Coder {
    private App app;

    private Coder(){
        System.out.println("调用Coder无参构造");
    }

    public Coder(App app) {
        System.out.println("调用Coder有参构造,参数app为:" + app.toString());
        this.app = app;
    }

    public App getApp() {
        return app;
    }

    public void setApp(App app) {
        System.out.println("调用Coder.setApp(), 参数app为: " + app.toString());
        this.app = app;
    }
}
public class BeanFactoryTest extends TestCase {
    /**
     * 直接编码方式
     */
    public void testRedirectCode() {
        DefaultListableBeanFactory beanRegistry = new DefaultListableBeanFactory();
        BeanFactory beanFactory = bindViaCode(beanRegistry);
        Coder coder = (Coder) beanFactory.getBean("coder");
        coder.getApp().say();

        /**
         * 输出为:
         * //通过构造方法注入的情况
         * 调用App无参构造
         * 调用Coder有参构造,参数app为:App{says='App'}
         * App.say():App
         *
         * //通过setter方式注入的情况下
         * 调用Coder无参构造
         * 调用App无参构造
         * 调用Coder.setApp(), 参数app为: App{says='App'}
         * App.say():App
         */
    }

    public static BeanFactory bindViaCode(BeanDefinitionRegistry registry){
        AbstractBeanDefinition appBeanDefinition = new RootBeanDefinition(App.class);
        AbstractBeanDefinition coderBeanDefinition = new RootBeanDefinition(Coder.class);

        //将beanDefinition注册到容器中
        registry.registerBeanDefinition("app", appBeanDefinition);
        registry.registerBeanDefinition("coder", coderBeanDefinition);

        //指定依赖关系
        //1、可以通过构造方法注入
//        ConstructorArgumentValues argumentValues = new ConstructorArgumentValues();
//        argumentValues.addIndexedArgumentValue(0, appBeanDefinition);
//        coderBeanDefinition.setConstructorArgumentValues(argumentValues);

        //2、可以通过setter方法注入
        MutablePropertyValues mutablePropertyValues = new MutablePropertyValues();
        mutablePropertyValues.addPropertyValue("app", appBeanDefinition);
        coderBeanDefinition.setPropertyValues(mutablePropertyValues);

        //绑定完成
        return (BeanFactory)registry;
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <!--这是 pom.xml文件 -->
    <groupId>com.me.sourcecode</groupId>
    <artifactId>spring-explore</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <spring.version>4.1.3.RELEASE</spring.version>
    </properties>


    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring.version}</version>
        </dependency>
    </dependencies>

</project>

1.3 原理 (摘自《spring揭秘》)

   打个比方说,BeanDefinitionRegistry就像图书馆的书架,所有的书是放在书架上的。虽然你
还书或者借书都是跟图书馆(也就是BeanFactory,或许BookFactory可能更好些)打交道,但书架才
是图书馆存放各类图书的地方。所以,书架相对于图书馆来说,就是它的“BookDefinitionRegistry”。


   每一个受管的对象,在容器中都会有一个BeanDefinition的实例(instance)与之相对应,该
BeanDefinition的实例负责保存对象的所有必要信息,包括其对应的对象的class类型、是否是抽象
类、构造方法参数以及其他属性等。当客户端向BeanFactory请求相应对象的时候,BeanFactory会
通过这些信息为客户端返回一个完备可用的对象实例。RootBeanDefinition和ChildBean-
Definition是BeanDefinition的两个主要实现类。

 

2、xml配置文件方式

2.1 项目结构(上面的基础上)

2.2 新增文件SpringBean.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" xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
       xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jee="http://www.springframework.org/schema/jee"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
        http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd
        http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring-1.2.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">

    <bean id="app" class="com.me.sourcecode.bean.App"></bean>

    <!--<bean id="coder" class="com.me.sourcecode.bean.Coder">-->
        <!--<constructor-arg index="0">-->
            <!--<ref bean="app" />-->
        <!--</constructor-arg>-->
    <!--</bean>-->

    <bean id="coder" class="com.me.sourcecode.bean.Coder">
        <property name="app" ref="app"></property>
    </bean>
</beans>

BeanFactoryTest类里,增加对xml文件配置方式的测试

/**
     * xml配置文件方式
     */
    public void testXmlFile(){
        DefaultListableBeanFactory beanRegistry = new DefaultListableBeanFactory();
        BeanFactory beanFactory = bindViaXmlFile(beanRegistry);
        Coder coder = (Coder) beanFactory.getBean("coder");
        coder.getApp().say();
    }

public static BeanFactory bindViaXmlFile(BeanDefinitionRegistry registry) {
        XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(registry);
        xmlBeanDefinitionReader.loadBeanDefinitions("classpath*:SpringBean.xml");
        return (BeanFactory) registry;
    }

2.3 原理(摘自《spring揭秘》)

  XmlBeanDefinitionReader负责读取Spring指定格式的XML配置文件并解析,之后将解析后的文件内
容映射到相应的BeanDefinition,并加载到相应的BeanDefinitionRegistry中(在这里是DefaultListableBeanFactory)

 

3、基于注解的方式

3.1 项目结构(不变)

3.2  有修改的内容

@Component
public class App {
    private String says = "App";

    private App(){
        System.out.println("调用App无参构造");
    }

    public App(String says) {
        System.out.println("调用App有参构造, 参数says为:" + says);
        this.says = says;
    }

    public void say(){
        System.out.println("App.say():" + says);
    }

    public String getSays() {
        return says;
    }

    public void setSays(String says) {
        this.says = says;
    }

    @Override
    public String toString() {
        return "App{" +
                "says='" + says + '\'' +
                '}';
    }
}
@Component
public class Coder {
    @Autowired
    private App app;

    private Coder(){
        System.out.println("调用Coder无参构造");
    }

    public Coder(App app) {
        System.out.println("调用Coder有参构造,参数app为:" + app.toString());
        this.app = app;
    }

    public App getApp() {
        return app;
    }

    public void setApp(App app) {
        System.out.println("调用Coder.setApp(), 参数app为: " + app.toString());
        this.app = app;
    }
}

SpringBean.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" xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
       xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jee="http://www.springframework.org/schema/jee"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
        http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd
        http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring-1.2.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">

    <context:component-scan base-package="com.me.sourcecode.bean" />
</beans>

BeanFactoryTest增加基于注解方式的测试

/**
     * 基于注解的方式
     */
    public void testAnnoation(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("SpringBean.xml");
        Coder coder = (Coder) applicationContext.getBean("coder");
        coder.getApp().say();

        /**
         * 输出为:
         * 调用App无参构造
         * 调用Coder无参构造
         *
         * App.say():App
         */
    }

3.3 原理  

  可以看到输出结果中,没有调用Coder.setApp()这一句,而又有App.say(): App这一句。它是Coder里面的app是怎么注入进入的呢?

 1) 通过SpringBean.xml文件的<context:component-scan base-package="com.me.sourcecode.bean" />,开始扫描这个路径,处理所有@Component注解标记的类(即App,Coder),生成对应的BeanDefinition

2)根据BeanDefinition创建Bean,此时Coder里面的app还是null,也就说还没有进行依赖注入

3)创建Bean之后,有个实例化Bean的流程。在这个流程中,AutowiredAnnotationBeanPostProcessor起了作用,通过反射的方式将App注入到Coder对象里面了。

反射 field.set(bean, value) ,此时bean是Coder的实例,value是App的实例
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值