Spring ioc原理

spring基础使用

Spring概念

下载:http://www.springsource.org/download

Spring用于解决具有依赖关系的对象创建问题。

例如有类Manager和类UserDao

public class Manager {

    

    private UserDao userDao;

    

    public Manager(UserDao userDao) {

        this.userDao = userDao;

    }

 

    public void save() {

        this.userDao.save();

    }

}

 

public class UserDao {

 

    public void save() {

        System.out.println("------------UserDao.save()-------------");

    }

 

}

则在创建Manager对象时必须首先创建UserDao对象,将它作为参数传递给构造方法,叫做Manager依赖于UserDao。实际业务中UserDao还可能依赖与其他类,如果都手工创建则很不方便,有改动时代码改动量会很大。可以在Spring的applicationContext.xml文件中配置依赖关系,这样创建Manager时,它所依赖的对象就会自动创建,叫做依赖注入。

spring配置

1、加入spring的库

    * SPRING_HOME/dist/spring.jar

    * SPRING_HOME/lib/jakarta-commons/commons-logging.jar

    * SPRING_HOME/lib/log4j/log4j-1.2.14.jar

2、拷贝spring配置文件applicationContext.xml和log4j.properties到src下,这两个配置文件放在spring的示例jpetstore中,

SPRING_HOME/samples/jpetstore/war/WEB-INF下。

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"

     xmlns:aop="http://www.springframework.org/schema/aop"

     xmlns:tx="http://www.springframework.org/schema/tx"

     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd

http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd

http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">

 

    <bean id="UserDao" class="com.aostaryh.dao.UserDao"/>

    <bean id="Manager" class="com.aostaryh.manager.Manager">

        <constructor-arg ref="UserDao">

    </bean>

    

</beans>

 

bean 的id是唯一标识,不能有重复,class指定对应的类。

constructor-arg属性表明创建Manager时Spring将自动创建ref="UserDao"对应的bean id的对象作为参数传入。

 

如果Manager不将UserDao作为构造函数,而是用setUserDao方法来设置,则可以把<constructor-arg ref="UserDao">改为

<property name="userDao" ref="UserDao"/>

表示在创建完Manager对象后,调用setUserDao方法将UserDao的对象设置进去。

 

客户端调用:

BeanFactory factory = new ClassPathXmlApplicationContext("applicationContext.xml");

        Manager manager = (Manager)factory.getBean("Manager");

        manager.save();

BeanFactory是一个接口ClassPathXmlApplicationContext的很多层父类已经是对它实现,其中就有ApplicationContext,因此用ApplicationContext factory声明也可以。

applicationContext.xml可以有多个,

* 构造new ClassPathXmlApplicationContext("applicationContext.xml")时参数可以传入一个字符串数组.

* spring在读取时会自动将几个文件的bean id内容合并。也可以这样写new ClassPathXmlApplicationContext("applicationContext-*.xml")用*模糊匹配加载xml。

* sping默认在加载配置文件时将所有bean创建并注入,可以配置让它用到哪个bean创建那个bean,方法:在beans标签中加入属性default-lazy-init="true",默认为false

普通属性注入

    applicationContext.xml文件中 :

* 注入引用采用ref,有两种写法

<property name="userDao" ref="UserDao"/>

或者

<property name="userDao">

<ref bean=" UserDao "/>

</property>

* 注入字符串或数字采用value,有两种写法

<property name="userDao" value="Hello"/>

或者

<property name="userDao">

<value>Hello</value>

</property>

* 注入list对象或者数组采用list

        <property name="listValue">

            <list>

                <value>list1</value>

                <value>list2</value>

            </list>

        </property>

* 注入set采用set

        <property name="setValue">

            <set>

                <value>set1</value>

                <value>set2"</value>

            </set>

        </property>

* 注入map采用map

        <property name="mapValue">

            <map>

                <entry key="key1" value="v1"/>

                <entry key="key2" value="v2"/>

            </map>

        </property>

由此可以看出,用spring可以代替自己写程序读取xml文件。spring能将配置的xml内容读取出来。

自定义属性注入

用户自定义属性和很多其他属性(例如将"2008-05-05"注入到java.util.Date类型的属性)在注入时是无法直接注入的,因为spring并不能转换所有的类型,这就需要用户自定义转换规则。

spring在遇到无法直接转换的属性时(例如将"2008-05-05"注入到java.util.Date类型),

        <property name="date">

            <value>2009-05-05</value>

        </property>

这时会去找

class="org.springframework.beans.factory.config.CustomEditorConfigurer"

的bean,这个就是用户自定义属性的类,然后找到它的map属性customEditors,看其中是否有key值和所需要的类型一致的entity(例如key="java.util.Date"就是一个符合的entity),找到符合的entity,就用其中的value值(或bean值)的类创建一个对象。例如:

<bean id="CustomEditorConfigurer" class="org.springframework.beans.factory.config.CustomEditorConfigurer">

        <property name="customEditors">

            <map>

                <entry key="java.util.Date">

                    <bean class="com.spr.userpropertyedit.UserPropertyEdit"/>

                </entry>

            </map>

        </property>

    </bean>

其中UserPropertyEdit类是用户写的,它继承了java.beans.PropertyEditorSupport,例如:

public class UserPropertyEdit extends PropertyEditorSupport {

    @Override

    public void setAsText(String text) throws IllegalArgumentException {

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

        Date date = null;

        try {

            date = sdf.parse(text);

        } catch (ParseException e) {

            // TODO 自动生成 catch 块

            e.printStackTrace();

        }

        this.setValue(date);

    }

}

其中的方法setAsText(String text)是覆写方法,spring会自动创建这个对象,并且调用这个方法,将value标签内的字符串"2009-05-05"作为参数传入,然后将这个类的value属性作为注入值,因此在这个方法中要用setValue(Object object)来设置返回作为注入的值。

SimpleDateFormat是日期处理类,创建对象时,可以将格式参数字符串,例如"yyyy-MM-dd"作为构造函数参数传入。它的parse(String s)返回Date类型对象。

公共属性注入

为减少注入时的重复书写,可以定义公共属性注入,需要的就集成它,例如:

<bean id="beanAbstract" abstract="true">
        <property name="id" value="222"/>
        <property name="name" value="TFC"/>
</bean>
<bean id="bean3" class="com.bjsxt.spring.Bean3" parent="beanAbstract">
        <property name="name" value="KKK"/>
        <property name="password" value="666666"/>
</bean>
<bean id="bean4" class="com.bjsxt.spring.Bean4" parent="beanAbstract"/>

其中beanAbstract加了属性abstract="true"表示其为公共属性bean,bean3、bean4继承了beanAbstractproperty定义,减少了重复书写,但子bean中如果也定义了和父bean相同的属性,则会覆盖父bean的。例如bean3name

spring Bean的作用域

<bean id="beana" class="com.bjsxt.spring.Beana" scope="prototype"/>

scope可以取值:    

    * singleton:每次调用getBean的时候返回相同的实例

    * prototype:每次调用getBean的时候返回不同的实例

默认singleton

根据名称和类型自动装配

Spring在装配属性时可以不用定义属性的装配规则,而采用根据bean的名称或类型自动查找一致的类生成对象来装配。

例如在beans标签里加上

default-autowire="byName"就能根据名称自动装配

但不推荐使用自动装配,因为这样从配置文件中就很难看出类之间的对应关系。

 

ioc原理分析

接口关系

 

 

简化关系:

BeanFactorybean容器的顶级接口,定义了一些bean的基本操作。

如:

//这里根据bean的名字和Class类型来得到bean实例,和上面的方法不同在于它会抛出异常:如果根据名字取得的bean实例的Class类型和需要的不同的话。

Object getBean(String name, Class requiredType) throws BeansException;

 

//这里提供对bean的检索,看看是否在IOC容器有这个名字的bean

boolean containsBean(String name);

 

//这里根据bean名字得到bean实例,并同时判断这个bean是不是单例

boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

 

//这里得到bean实例的Class类型

Class getType(String name) throws NoSuchBeanDefinitionException;

 

//这里得到bean的别名,如果根据别名检索,那么其原名也会被检索出来

String[] getAliases(String name);

BeanFactory的三个子接口是:ListableBeanFactory、HierarchicalBeanFactory、AutowireCapableBeanFactory。(简称HAL)

 

DefaultListableBeanFactory编程式方式使用ioc

BeanFactory-ConfigurableListableBeanFactory-DefaultListableBeanFactory是ioc的核心继承路线,其中DefaultListableBeanFactory是一个ioc容器的基础实现,它实现ioc的核心功能,后面的ApplicationContext等接口的实现都是在对象里面放了一个DefaultListableBeanFactory成员变量,getBean等操作都会DefaultListableBeanFactory对应的方法。如:

通过编程式方式使用DefaultListableBeanFactory:

ClassPathResource resource = new ClassPathResource("a.xml");

DefaultListableBeanFactory factory = new DefaultListableBeanFactory();

XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);

reader.loadBeanDefinitions(resource);

B b = (B)factory.getBean("b");

 

XmlBeanDefinitionReader创建时放入factory作为参数,然后通过loadBeanDefinitions读取resource即完成初始化。

resource是配置文件路径的封装,也就是用来定位资源位置的。

 

BeanDefinition

所有的bean都会封装成BeanDefinition的形式放入ioc容器,Beandefinition是一个接口,它提供了操作bean的公共方法:

如:

很多都是配置文件里面bean标签的属性。

ApplicationContext对Beanfactory的扩展

ApplicationContext继承了ListableBeanFactory、HierarchicalBeanFactory的同时继承EnvironmentCapable, MessageSource, ApplicationEventPublisher, ResourcePatternResolver等接口,使其具有加载资源、监听事件等能力。ApplicationContext虽然继承了Beanfactory,但它的实现类并非直接实现getBean等BeanFactory中的方法,而是在里面放了一个DefaultListableBeanFactory作为成员变量,实际的bean对象也是放在DefaultListableBeanFactory这个容器里面的。例如BeanPostProcesser扩展的可以在bean创建前后执行特定代码,也就是在操作DefaultListableBeanFactory成员变量的getBean前后加事件的方式实现。

 

ApplicationContext的子接口有ConfigurableApplicationContextWebApplicationContext2个(简称WC),而它们的最终实现有3个:ClassPathXmlApplicationContext、FileSystemXmlApplicationContext、XmlWebApplicationContext. (简称CFX)

 

FileSystemXmlApplicationContext初始化流程分析

初始化主要做的事就是读取spring的bean配置文件,转换为BeanDefinition的形式,放到一个ConcurrentHashMap里。

 

FileSystemXmlApplicationContext的使用,如:

        BeanFactory beanFactory = new FileSystemXmlApplicationContext("src/main/resources/a.xml");

//        BeanFactory beanFactory = new FileSystemXmlApplicationContext("d:/b.xml");

        System.out.println(beanFactory.containsBean("ttt1"));

        System.out.println(beanFactory.getType("ttt1"));

 

它的构造函数:

    public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)

            throws BeansException {

 

        super(parent);

        setConfigLocations(configLocations);

        if (refresh) {

            refresh();

        }

    }

最终调用了AbstractApplicationContext的refresh()方法

通过前面的编程式使用ioc可以看出,这里需要创建一个XmlBeanDefinitionReader,并且以本对象的DefaultListableBeanFactory成员变量作为参数传入,创建Resource对象(ResourceLoader负责将String类型的路径转化为Resource对象),然后调用XmlBeanDefinitionReaderloadBeanDefinitions(resource)载入springbean配置,加载bean

 

BeanDefinition资源定位

也就是创建Resource资源,通过ResourceLoader的getResource(String location)将文件路径解析成Resource的过程。根据不同的location类型(如classpath的,文件路径形式的等),Resource也可以分为不同的形式,如ClassPathResourceFileSystemResource等。

 

这一步在DefaultListableBeanFactory使用中是用户手动创建的,在ApplicationContext使用中是由spring创建的。

 

跟踪方法:

入口是AbstractRefreshableApplicationContext类的refreshBeanFactory()方法。

这里可以看出确实是DefaultListableBeanFactory

refreshBeanFactory()方法首先将原来的beanFactory销毁,然后创建新的,最后复制给本对象的成员变量。

然后是创建XmlBeanDefinitionReader,调用它的loadBeanDefinitions方法。

不过这里的参数不是Resource,而是String类型的,需要做转换:

可以看出这里是ResourceLoader负责将路径转换为Resource,其实就是根据不同的路径类型创建不同的Resource对象,如ClassPathResource就是将classpath:前缀去掉作为构造参数创建ClassPathResource对象。

 

BeanDefinition资源载入

资源载入和注册都在XmlBeanDefinitionsLoader的loadBeanDefinitions方法中进行,因此资源载入和注册是DefaultListableBeanFactory要进行的操作,而不是ApplicaionContext特有的操作。

 

资源载入也就是解析定位到的spring配置文件,将其解析成BeanDefinitionHolder的形式,载入到ioc容器中(此时还没有注册到ioc容器的map上)。

跟踪代码:

此时将Resource资源以io流的方式取出,为读取文件做准备。

 

DocumentLoader负责读取配置文件,以Document的形式供后面的解析使用。

 

最终是BeanDefinitionParserDelegate负责解析DocumentElement

 

 

这里上面一步是解析Element具体过程,下面一步就是将BeanDefinitionHolder的BeanDefinition注册到ioc容器的map。

 

这就是BeanDefinitionParserDelegate解析Element的具体过程,spring初始化经常看到的几种异常类型在这里都有声明。

 

(引用:refresh()方法的目的是加载或刷新bean的配置(xml、properties等)。

主要步骤是:读取配置、加载bean、注册bean到beanFactory、初始化事件监听。)

BeanDefinition注册

就是将BeanDefinition放入到ioc的ConcurrentHashMap里

这里首先检查是否已经有该BeanDefinition,如果有,判断该BeanDefinition是否允许覆盖,如果不允许,则抛异常,允许则覆盖。最后将BeanDefinition放入到ioc的ConcurrentHashMap里。

getBean创建Bean对象和依赖注入

创建Bean对象是由getBean方法触发的,它会查找到对应BeanDefinition,然后创建Bean对象,并且会自动创建所依赖的bean,设置到对应的属性上。

 

首先到单例bean的缓存中查找bean,如果找到就使用

可以看出,单例bean实例是以beanName为key放到一个HashMap中的。

这个ObjectFactory其实就是FactoryBean,使用工厂模式,通过getObject()方法取得目标bean对象的实例。

 

 

 

如果本容器里没有找到BeanDefinition配置,则将创建bean的任务交给父容器。

 

取出所依赖的beanDefinition,然后通过getBean触发依赖的beanDefinition的实例化。

 

调用createBean方法创建bean,传入了BeanDefinition作为参数。

 

实际调用到了doCreateBean

 

createBeanInstance负责创建bean对象,populateBean负责依赖注入。

 

进入到createBeanInstance里面:

 

 

进入populateBean方法里面:

这里就是设置属性的地方。

spring的前置、后置处理器

BeanFactoryPostProcessor和BeanPostProcessor

 

BeanFactoryPostProcessor是一个接口,只有一个方法    

 

将实现BeanFactoryPostProcessor的类作为bean配置到spring中。spring创建beanfactory时会自动回调postProcessBeanFactory方法。用于控制BeanDefinition的生成。

 

BeanFactoryPostProcessor可以有多个实现,spring创建beanfactory会依次调用每个类的postProcessBeanFactory方法。

如:

 

 

 

BeanPostProcessor与BeanFactoryPostProcessor类似它也是一个接口,里面有2个方法,只不过它是控制bean对象的生成,在bean对象生成前和生成后回调。

如:

BeanFactoryPostProcessor的应用
创建可以获取容器bean的SpringUtils

由于BeanFactoryPostProcessor的回调方法会传入beanFactory,因此可以写一个SpringUtils实现这个接口,getBean时去调用beanFactory的getBean取得spring的bean对象。

 

如:

public class SpringUtils implements BeanFactoryPostProcessor {

 

    private static BeanFactory beanFactory;

 

    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

        SpringUtils.beanFactory = beanFactory;

    }

    

    public static Object getBean(String beanName) {

        return beanFactory.getBean(beanName);

    }

 

}

 

 

设置spring可读取远程配置文件

例子:spring配置文件中,远程读取properties配置

默认spring配置文件中加载properties只能是本地文件,可以通过实现BeanFactoryPostProcessor接口扩展,使其加载配置从远程读取。

1、实现BeanFactoryPostProcessor 接口,会被Application contexts自动发现 
2、BeanFactoryPostProcessor 仅仅对 bean definitions 发生关系,不能对bean instances 交互,对bean instances 的交互,由BeanPostProcessor的实现来处理 
3、PropertyResourceConfigurer 是BeanFactoryPostProcessor一个典型的实现 

只要继承PropertyResourceConfigurer ,同时实现InitializingBean接口即可。

 

MyFilePlaceHolderBeanFactoryPostProcessor.java:

package com.tests;

 

import java.util.ArrayList;

import java.util.List;

import java.util.Properties;

 

import org.springframework.beans.factory.InitializingBean;

import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;

import org.springframework.core.io.support.PropertiesLoaderUtils;

 

public class MyFilePlaceHolderBeanFactoryPostProcessor extends PropertyPlaceholderConfigurer implements InitializingBean {

 

    public void afterPropertiesSet() throws Exception {

        List<Properties> list = new ArrayList<Properties>();

        // 此处模拟从远程获取配置信息

        Properties p = PropertiesLoaderUtils.loadAllProperties("config.properties");

        list.add(p);

        // 设置远程取得的List<Properties>列表

        setPropertiesArray(list.toArray(new Properties[list.size()]));

    }

}

 

UserService.java:

package com.tests;

 

public class UserService {

 

    public UserService() {

        System.out.println("UserService 构造函数 ");

    }

 

    private String username;

    private String password;

 

    public String getUsername() {

        return username;

    }

 

    public String getPassword() {

        return password;

    }

 

    public void setUsername(String username) {

        System.out.println("UserService setUsername " + username);

        this.username = username;

    }

 

    public void setPassword(String password) {

        System.out.println("UserService setPassword " + password);

        this.password = password;

    }

 

    @Override

    public String toString() {

        return "UserService [username=" + username + ", password=" + password + "]";

    }

}

 

Test.java

package com.tests;

 

import org.springframework.context.support.ClassPathXmlApplicationContext;

 

public class Test {

 

    public static void main(String[] args) {

        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:a.xml");

        UserService userService = applicationContext.getBean(UserService.class);

        String password = userService.getPassword();

        applicationContext.destroy();

        System.out.println(password);

    }

}

 

a.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:aop="http://www.springframework.org/schema/aop"

    xmlns:tx="http://www.springframework.org/schema/tx"

    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd

http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd

http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">

 

    <bean id="user" class="com.tests.UserService">

        <property name="username" value="${username}" />

        <property name="password" value="${password}" />

    </bean>

 

    <bean id="myFactoryPostProcessor" class="com.tests.MyFilePlaceHolderBeanFactoryPostProcessor" />

</beans>

 

config.properties

username=kkk

password=123456

 

pom.xml:

<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>

    <groupId>com.test</groupId>

    <artifactId>tests</artifactId>

    <version>0.0.1-SNAPSHOT</version>

    <name>Ts</name>

    <dependencies>

        <dependency>

            <groupId>org.springframework</groupId>

            <artifactId>spring-core</artifactId>

            <version>3.2.13.RELEASE</version>

        </dependency>

        <dependency>

            <groupId>org.springframework</groupId>

            <artifactId>spring-context</artifactId>

            <version>3.2.13.RELEASE</version>

        </dependency>

        <dependency>

            <groupId>org.springframework</groupId>

            <artifactId>spring-beans</artifactId>

            <version>3.2.13.RELEASE</version>

        </dependency>

    </dependencies>

</project>

 


调用入口:
 

InitializingBean

接口方式实现

InitializingBean是一个接口,只有一个方法:afterPropertiesSet

 

使用方式是bean直接继承这个接口,实现它的方法,afterPropertiesSet会在依赖注入完成后被回调。

如:

 

B依赖了C,B实现了InitializingBean接口,第一次输出c=null是因为此时B只是创建了对象,还没有完成依赖注入,c还是null,第二次输出的c不为null是因此在afterPropertiesSet方法输出,此方法在依赖注入完成后才被调用。

 

afterPropertiesSetBeanPostProcessor的调用顺序如下:

postProcessBeforeInitialization

afterPropertiesSet

postProcessAfterInitialization

 

配置方式实现

 

接口方式使bean跟spring绑定了,必须实现InitializingBean接口,不太好。可以将初始化方法配置到bean标签的init-method属性中,摆脱对InitializingBean接口的依赖,如:

 

同理,在bean销毁的时候,也可以有回调方法,对应bean标签的destroy-method属性,如:

源代码分析

 

可以看出initializeBean是在populateBean之后调用的,因此是在依赖注入完成以后才执行。

 

Aware接口

Aware是个空接口,其下有很多子接口

在spring中,这些接口的实现类的实现方法会被spring回调。

 

 

BeanNameAware、BeanClassLoaderAware、BeanFactoryAware接口的回调

其中BeanNameAware、BeanClassLoaderAware、BeanFactoryAware的实现类在bean完成依赖注入以后都会被自动回调方法:

 

ApplicationContextAwareProcessor的回调

ApplicationContextAware等几个子接口实现类的方法被回调则是因为ApplicationContextAwareProcessor的缘故

 

ApplicationContextAwareProcessor的加载则是在AbstractApplicationContextrefresh方法里

ServletContextAwareProcessor的回调

与ApplicationContextAwareProcessor类似,只不过ServletContextAwareProcessor不是在prepareBeanFactory设置,而是在下面一个方法postProcessBeanFactory设置的。

 

Web容器中使用的是XmlWebApplicationContext,在它的父类AbstractRefreshableWebApplicationContext中实现了postProcessBeanFactory方法,而这个方法也是refresh回调的。

 

使用测试

这里自动回调了setBeanName方法。

lazy-init属性

bean的Lazy-init属性默认为false,也就是在初始化完成以后就会自动创建singleton的bean,而不需要等到使用的时候用户去getBean时才创建。

 

ps:lazy-init也只是对singleton的单件bean起作用,因为多实例的bean每次使用都需要创建新对象。

 

源代码如下:

FactoryBean

FactoryBean是一个接口,用户工厂模式,里面有一个重要方法getObject(),通过这个方法取得真实的bean对象。

 

源代码:

注解方式使用 (autowiring的实现)

使用注解方式可以减少配置,spring配置文件声名略有不同:

a.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:mvc="http://www.springframework.org/schema/mvc"

    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:util="http://www.springframework.org/schema/util"

    xmlns:context="http://www.springframework.org/schema/context"

    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd

http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd

http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd

http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd

http://www.springframework.org/schema/aop

http://www.springframework.org/schema/aop/spring-aop.xsd"

    default-autowire="byName">

    <context:component-scan base-package="com.test.springioc" />

</beans>

其中context:component-scan表示扫描bean包的根路径

 

 

@service表示这是一个spring的bean

@autowired表示自动装配的属性。

@PostContruct修饰方法等价于配置的init-method属性,表示依赖注入完成以后执行的初始化方法。

输出的c不为null,说明注入成功了

 

autowiring注入实现过程分析:

在populate()方法依赖注入时,会检查autowiring注解的属性,然后通过属性名字创建bean,注入到属性中。

根据名称或者类型装配。

 

创建bean,设置到对应属性。

 

bean的依赖检查

populatebean在依赖关系注入前,会进行检查,确保BeanDefinition的依赖关系正确:

 

扩展点:

 

 

BeanFactoryPostProcessor

创建BeanFactory时调用

 

 

BeanPostProcessor

创建Bean时调用

 

 

InitializingBean

创建Bean时调用

 

DisposableBean

销毁Bean时调用

 

FactoryBean

用户可以自定义的Bean

 

posted @ 2020-12-16 13:13  吴克兢  阅读(98)  评论(0)    收藏  举报