BeanFactory和ApplicationContext区别

BeanFactory是Spring框架的中IOC容器的顶层接口,它只是用来定义一些基础功能和一些基础规范,ApplicationContext是它的子接口,所以ApplicationContext具备BeanFactory提供的全部功能的。通常我们称BeanFactory为Spring IOC的基础容器,ApplicationContext是容器的高级接口,比BeanFactory要拥有更多的功能,比如国际化支持和资源访问等(xml,Java配置类)等等。
BeanFactory结构树.png

启动IOC容器

Java环境下启动IOC容器

  1. ClassPathXMLApplicationContext: 从类的更路径下架子配置文件(推荐使用)
  2. FileSystemXMlApplicationContext: 从磁盘路劲上加载配置文件
  3. AnnotationConfigApplicationContext: 纯注解模式下启动Spring容器

    1. // 通过读取classpath下的xml文件来启动容器(xml模式SE应用下推荐)
    2. ClassPathXmlApplicationContext applicationContext = new
    3. ClassPathXmlApplicationContext("classpath:applicationContext.xml");
    4. // 不推荐使用
    5. //ApplicationContext applicationContext1 = new
    6. FileSystemXmlApplicationContext("文件系统的绝对路径");
    7. // 第一次getBean该对象
    8. Object accountPojo = applicationContext.getBean("accountPojo");

    Web环境下启动IOC容器

  4. 从XML启动容器

    1. <!DOCTYPE web-app PUBLIC
    2. "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    3. "http://java.sun.com/dtd/web-app_2_3.dtd" >
    4. <web-app>
    5. <display-name>Archetype Created Web Application</display-name>
    6. <!--配置Spring ioc容器的配置⽂件-->
    7. <context-param>
    8. <param-name>contextConfigLocation</param-name>
    9. <param-value>classpath:applicationContext.xml</param-value>
    10. </context-param>
    11. <!--使⽤监听器启动Spring的IOC容器-->
    12. <listener>
    13. <listenerclass>org.springframework.web.context.ContextLoaderListener</listenerclass>
    14. </listener>
    15. </web-app>

    从配置类启动容器

    <!DOCTYPE web-app PUBLIC
    "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd" >
    <web-app>
      <display-name>Archetype Created Web Application</display-name>
    <!--告诉ContextloaderListener知道我们使⽤注解的⽅式启动ioc容器-->
    <context-param>
      <param-name>contextClass</param-name>
      <paramvalue>org.springframework.web.context.support.AnnotationConfigWebAppli
     cationContext</param-value>
    </context-param>
    <!--配置启动类的全限定类名-->
    <context-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>com.lagou.edu.SpringConfig</param-value>
    </context-param>
    <!--使⽤监听器启动Spring的IOC容器-->
    <listener>
          <listenerclass>org.springframework.web.context.ContextLoaderListener</listenerclass>
    </listener>
    </web-app>
    

    纯XML模式

    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
    https://www.springframework.org/schema/beans/spring-beans.xsd">
    

    实例化Bean的方式

  5. ⽅式⼀:使⽤⽆参构造函数

在默认情况下,它会通过反射调⽤⽆参构造函数来创建对象。如果类中没有⽆参构造函数,将创建失败。

<!--配置service对象-->
<bean id="userService" class="com.lagou.service.impl.TransferServiceImpl">
</bean>
  1. 方式二: 使用静态方法创建 ``` public class CreateBeanFactory { public static ConnectionUtils getInstanceStatic() {
     return new ConnectionUtils();
    
    } }
```
  <bean id="connectionUtils" class="com.lagou.edu.factory.CreateBeanFactory" 
  factory-method="getInstanceStatic"/>
  1. 方法三:实例化方法

    public class CreateBeanFactory {
         //每次调用都要实例化 CreateBeanFactory
     public ConnectionUtils getInstance() {
         return new ConnectionUtils();
     }
    }
    
    <bean id="createBeanFactory" class="com.lagou.edu.factory.CreateBeanFactory"></bean>
    <bean id="connectionUtils" factory-bean="createBeanFactory" factory-method="getInstance"/>
    
  2. .通过FactoryBean创建Bean ``` public interface FactoryBean {

    /**

    • 返回创建好的对象 */ @Nullable T getObject() throws Exception;

      /**

    • 返回需要创建的对象的类型 */ @Nullable Class<?> getObjectType();

      /**

      • bean是否是单例的 **/ default boolean isSingleton() { return true; }

}

<a name="q1S9e"></a>
## Bean的作用范围和生命周期
<a name="eOWMV"></a>
## 作用范围
Spring框架管理Bean对象的创建时,Bean对象默认都是单例的,但是它支持配置的方式改变作用范围。在配置中,通过 Scope 来定义Bean对象的作用范围

| scope | 作用范围 |
| --- | --- |
| singleton | 单例,IOC容器只有一个该类对象 |
| prototype | 多例,每次使用该类的对象(getBean),都返回给一个新的对象 |

在开发中用的最多便是这两个作用范围,还有request、Session、application、websocket等。
<a name="4ghFg"></a>
## 不同作用范围的生命周期

1. 单例模式:**singleton**

对象出⽣:当创建容器时,对象就被创建了。<br />对象活着:只要容器在,对象⼀直活着。<br />对象死亡:当销毁容器时,对象就被销毁了<br />⼀句话总结:单例模式的bean对象⽣命周期与容器相同。

2. 多例模式:**prototype**

对象出⽣:当使⽤对象时,创建新的对象实例。<br />对象活着:只要对象在使⽤中,就⼀直活着。<br />对象死亡:当对象⻓时间不⽤时,被java的垃圾回收器回收了。<br />⼀句话总结:多例模式的bean对象,spring框架只负责创建,不负责销毁。
<a name="fHt0y"></a>
## Bean标签属性
在基于xml的IoC配置中,bean标签是最基础的标签。它表示了IoC容器中的⼀个对象。换句话<br />说,如果⼀个对象想让spring管理,在XML的配置中都需要使⽤此标签配置,Bean标签的属性如下:<br />**id**属性: ⽤于给bean提供⼀个唯⼀标识。在⼀个标签内部,标识必须唯⼀。<br />**class**属性:⽤于指定创建Bean对象的全限定类名。<br />**name**属性:⽤于给bean提供⼀个或多个名称。多个名称⽤空格分隔。<br />**factory-bean**属性:⽤于指定创建当前bean对象的⼯⼚bean的唯⼀标识。当指定了此属性之后,<br />class属性失效。<br />**factory-method**属性:⽤于指定创建当前bean对象的⼯⼚⽅法,如配合factory-bean属性使⽤,<br />则class属性失效。如配合class属性使⽤,则⽅法必须是static的。<br />**scope**属性:⽤于指定bean对象的作⽤范围。通常情况下就是singleton。当要⽤到多例模式时,<br />可以配置为prototype。<br />**init-method**属性:⽤于指定bean对象的初始化⽅法,此⽅法会在bean对象装配后调⽤。必须是<br />⼀个⽆参⽅法。<br />**destory-method**属性:⽤于指定bean对象的销毁⽅法,此⽅法会在bean对象销毁前执⾏。它只<br />能为scope是singleton时起作⽤。
<a name="oHRCS"></a>
## 依赖注入
<a name="RQxB8"></a>
### 依赖注入分类

1. 按照注入的方式分类

构造函数注入:顾名思义,就是利用待参构造实现对类成员的数据赋值<br />set方法注入:他是通过类成员的set方法实现数据注入。(使用最多)

2. 按照注入的数据类型分类

基本类型和String:注入的数据类型是基本类型或者是字符串类型的数据<br />其他Bean类型:注⼊的数据类型是对象类型,称为其他Bean的原因是,这个对象是要求出现在IoC容器 中的。那么针对当前Bean来说,就是其他Bean了。<br />复杂类型(集合类型):注⼊的数据类型是Aarry,List,Set,Map,Properties中的⼀种类型

<a name="JhBrP"></a>
#### Set方法注入

public class JdbcAccountDaoImpl implements AccountDao {

private ConnectionUtils connectionUtils;
private String name;
private int sex;
private float money;

public void setConnectionUtils(ConnectionUtils connectionUtils) {
    this.connectionUtils = connectionUtils;
}

public void setName(String name) {
    this.name = name;
}

public void setSex(int sex) {
    this.sex = sex;
}

public void setMoney(float money) {
    this.money = money;
}

}

```
set注入使用property标签,如果注入的是另外一个bean那么使用ref属性,如果注入的是普通值那么使用的是value属性
 <bean id="connectionUtils" class="com.lagou.edu.utils.ConnectionUtils"/>
<property name="ConnectionUtils" ref="connectionUtils"/>
<property name="name" value="zhangsan"/>
<property name="sex" value="1"/>
<property name="money" value="100.3"/>

构造方法注入

    public JdbcAccountDaoImpl(ConnectionUtils connectionUtils, String name, int sex, float money) {
        this.connectionUtils = connectionUtils;
        this.name = name;
        this.sex = sex;
        this.money = money;
    }
<constructor-arg name="connectionUtils" ref="connectionUtils"/>
<constructor-arg name="name" value="zhangsan"/>
<constructor-arg name="sex" value="1"/>
<constructor-arg name="money" value="100.6"/>

复杂类型注入

        private String[] myArray;
    private Map<String,String> myMap;
    private Set<String> mySet;
    private Properties myProperties;

    public void setMyArray(String[] myArray) {
        this.myArray = myArray;
    }

    public void setMyMap(Map<String, String> myMap) {
        this.myMap = myMap;
    }

    public void setMySet(Set<String> mySet) {
        this.mySet = mySet;
    }

    public void setMyProperties(Properties myProperties) {
        this.myProperties = myProperties;
    }
 <!--set注入注入复杂数据类型-->
        <property name="myArray">
            <array>
                <value>array1</value>
                <value>array2</value>
                <value>array3</value>
            </array>
        </property>

        <property name="myMap">
            <map>
                <entry key="key1" value="value1"/>
                <entry key="key2" value="value2"/>
            </map>
        </property>

        <property name="mySet">
            <set>
                <value>set1</value>
                <value>set2</value>
            </set>
        </property>

        <property name="myProperties">
            <props>
                <prop key="prop1">value1</prop>
                <prop key="prop2">value2</prop>
            </props>
        </property>

XML与注解相结合

注意:
1)实际企业咖啡中,纯XML模式使用已经很少了
2)引入注解功能,不需要引入额外的jar包
3)xml+注解结合模式,xml文件依然存在,所以spring IOC容器启动仍然从加载 xlm 开始。
4)哪些bean的定义写在xml中,哪些bean的定义使用注解
第三方jar中bean定义在xml,比如德鲁伊数据连接池
自己开发的bean定义使用注解

xml中标签与注解的对应(IOC)

xml形式 对应的注解形式
标签

| @Component(“accountDao”),注解加在类上
bean的id属性内容直接配置在注解后⾯如果不配置,默认定义个这个bean的id为类
的类名⾸字⺟⼩写;
另外,针对分层代码开发提供了@Componenet的三种别名@Controller、
@Service、@Repository分别⽤于控制层类、服务层类、dao层类的bean定义,这
四个注解的⽤法完全⼀样,只是为了更清晰的区分⽽已 | | 标签的 scope属 性 | @Scope(“prototype”),默认单例,注解加在类上 | | 标签的 init-method 属性 | @PostConstruct,注解加在⽅法上,该⽅法就是初始化后调⽤的⽅法 | | 标签的 destory-method 属性 | @PreDestory,注解加在⽅法上,该⽅法就是销毁前调⽤的⽅法 |

依赖注入的注解实现方式

@Autowrited (推荐使用)

public class TransferServiceImpl {
 @Autowired
 private AccountDao accountDao; 
 }

如上代码所示,这样装配回去spring容器中找到类型为AccountDao的类,然后将其注⼊进来。这样会产⽣⼀个问题,当⼀个类型有多个bean值的时候,会造成⽆法选择具体注⼊哪⼀个的情况,这个时候我们需要配合着@Qualififier使⽤。
@Qualififier告诉Spring具体去装配哪个对象

public class TransferServiceImpl {
 @Autowired
 @Qualifier(name="jdbcAccountDaoImpl") 
 private AccountDao accountDao; 
 }

在xml文件中开启注解扫描或者引入外部资源

    <!--开启注解扫描,base-package指定扫描的包路径-->
    <context:component-scan base-package="com.lagou.edu"/>

    <!--引入外部资源文件-->
    <context:property-placeholder location="classpath:jdbc.properties"/>

纯注解

改造xm+注解模式,将xml中遗留的内容全部以注解的形式迁移出去,最终删除xml,从Java配置类启动
对应注解
@Confifiguration 注解,表名当前类是⼀个配置类
@ComponentScan 注解,替代 context:component-scan
@PropertySource,引⼊外部属性配置⽂件
@Import 引⼊其他配置类
@Value 对变量赋值,可以直接赋值,也可以使⽤ ${} 读取资源配置⽂件中的信息
@Bean 将⽅法返回对象加⼊ SpringIOC 容器

使用案例

@Configuration
@ComponentScan({"com.lagou.edu"})
@PropertySource({"classpath:jdbc.properties"})
/*@Import()*/
public class SpringConfig {

    @Value("${jdbc.driver}")
    private String driverClassName;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;


    @Bean("dataSource")
    public DataSource createDataSource(){
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setDriverClassName(driverClassName);
        druidDataSource.setUrl(url);
        druidDataSource.setUsername(username);
        druidDataSource.setPassword(password);
        return  druidDataSource;
    }

配置jdbc.properties文件

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/bank
jdbc.username=root
jdbc.password=123456

Java测试代码

@Test
public void testIoC() throws Exception {
    // 通过读取classpath下的xml文件来启动容器(xml模式SE应用下推荐)
    ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);

    AccountDao accountDao = (AccountDao) applicationContext.getBean("accountDao");

    System.out.println(accountDao);
}

如果是web项目,配置web.xml文件

  <!--告诉ContextloaderListener知道我们使用注解的方式启动ioc容器-->
  <context-param>
    <param-name>contextClass</param-name>
    <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
  </context-param>
  <!--配置启动类的全限定类名-->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>com.lagou.edu.SpringConfig</param-value>
  </context-param>
  <!--使用监听器启动Spring的IOC容器-->
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>