详细的描述了Spring中Bean的实例化与依赖注入。

Bean的实例化

构造方法

Spring创建Bean的时候调用无参构造。(有参构造会报错,私有无参也可以,底层使用了反射)

注意:Spring中的报错从下向上看,直到找到有用的信息。

注意:若不存在无参构造方法,会抛出异常:BeanCreationException

添加无参构造后:
运行结果:
SSM02-01构造方法

静态工厂

创建对象不需要自己new,创建一个工厂创建对象达到解耦的效果

样例代码:

package wang.factory;

import wang.dao.Dao;
import wang.dao.impl.DaoImpl;

public class DaoFactory {
public static Dao getDao() {
System.out.println("factory set up ...");
return new DaoImpl();
}
}

配置文件添加如下代码:

<bean id="daoFactory" class="wang.factory.DaoFactory" factory-method="getDao"/>

主函数:

package wang;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import wang.dao.Dao;

public class App3 {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
Dao dao = (Dao) ctx.getBean("daoFactory");
dao.save();
}
}

运行结果:

SSM02-02静态工厂

实例工厂

工厂代码同上

配置文件修改为如下代码:

<bean id="daoFactorytemp" class="wang.factory.DaoFactory"/>                 <!-- 创建工厂bean -->
<bean id="daoFactory" factory-bean="daoFactorytemp" factory-method="getDao"/>
<!-- factory-bean指定工厂bean -->

第一行为一个无用的bean,改良后即为第四种方法

主函数不变

运行结果:

SSM02-03FactoryBean

FactoryBean(重要!)

在第三种方法存在两个问题
一、factory-bean属性使用时会创建一个无用的Bean
二、factory-method属性方法名不固定,非动态实现

因此,对此方法做了改良

factory实现一个接口FactoryBean

工厂代码

package wang.factory;

import org.springframework.beans.factory.FactoryBean;
import wang.dao.Dao;
import wang.dao.impl.DaoImpl;

public class DaoFactoryBean implements FactoryBean<Dao> {
// 代替原始实例工厂创建对象的方法
@Override
public Dao getObject() throws Exception {
return new DaoImpl();
}
// 得到Bean的类型
@Override
public Class<?> getObjectType() {
return Dao.class;
}
// 设置Bean是否单例子,return true为单例,false为非单例
// 该方法一般不重写
/*@Override
public boolean isSingleton() {
return true;
}*/
}

配置文件修改为如下代码:

<bean id="daoFactory" class="wang.factory.DaoFactoryBean"/>

主函数不变

运行结果:

SSM02-03FactoryBean

补充:Bean的生命周期

控制生命周期

方法一:

控制方法代码:

public static DaoImpl implements Dao {
public void save() {
System.out.println("Dao save ... ")
}
public void init() {
System.out.println("Dao init ... ")
}
public void destroy() {
System.out.println("Dao destroy ... ")
}
}

配置控制方法:

<bean id="Dao" class="wang.dao.impl.DaoImpl" init-method="init" destroy-method="destory"/>

方法二

实现InitializingBean, DisposableBean接口

public static DaoImpl implements Dao, InitializingBean, DisposableBean {
public void save() {
System.out.println("Dao save ... ")
}
public void init() throws Exception {
System.out.println("Dao init ... ")
}
public void destroy() throws Exception {
System.out.println("Dao destroy ... ")
}
}
生命周期

初始化容器
1.创建对象(内存分配)
2.执行构造方法
3.执行属性注入( set操作)
4.执行bean初始化方法

使用bean
1.行业务操作

关闭/销毁容器
1.执行bean销毁方法

注:销毁的时机:容器关闭前触发bean的销毁
关闭容器方式:
手工关闭容器
ConfigurableApplicationContext接口close()

操作注册关闭钩子,在虚拟机退出前先关闭容器再退出虚拟机
ConfigurableApplicationcontext接口registerShutdownHook ()操作

依赖注入

setter注入

引用类型

详情见博客 SSM01-Spring中的Bean

步骤如下
1.在bean中定义引用类型属性并提供可访问的set方法
2.配置中使用property标签ref属性注入引用类型对象

简单类型

步骤如下
1.在bean中定义引用类型属性并提供可访问的set方法
2.配置中使用property标签value属性注入简单类型数据

构造器注入

引用类型(仅做了解)

步骤如下
1.在bean中定义引用类型属性并提供可访问的构造方法
2.配置中使用constructor-arg标签ref属性注入引用类型对象

简单类型

步骤如下
1.在bean中定义引用类型属性并提供可访问的set方法
2.配置中使用property标签value属性注入简单类型数据
注意:
配置中使用constructor-arg标签type属性设置按形参类型注入
配置中使用constructor-arg标签index属性设置按形参位置注入

依赖注入方式的选择(总结自黑马程序员,侵删)

1.强制依赖使用构造器进行,使用setter注入有概率不进行注入导致null对象出现
2.可选依赖使用setter注入进行,灵活性强
3.Spring框架倡导使用构造器,第三方框架内部大多数采用构造器注入的形式进行数据初始化,相对严谨
4.如果有必要可以两者同时使用,使用构造器注入完成强制依赖的注入,使用setter注入完成可选依赖的注入
5.实际开发过程中还要根据实际情况分析,如果受控对象没有提供setter方法就必须使用构造器注入
6.自己开发的模块推荐使用setter注入

自动装配(优先级低于setter注入与构造器注入)

IoC容器根据bean所依赖的资源在容器中自动查找并注入到bean中的过程称为自动装配

自动装配方式

按类型(常用)(不能对简单类型装配)
<bean id="daoFactory" class="wang.dao.impl.DaoImpl" autowire="byType"/>

注意:需要set方法

注意:按类型(byType)时,同类型的应该只有一个bean,否则分不清。

按名称(set方法第一个字母改为小写的名称,即标椎的变量名)
<bean id="daoFactory" class="wang.dao.impl.DaoImpl" autowire="byName"/>

注意:因为变量名与byName耦合度高,不建议使用。

按构造方法

集合注入(主要学习格式)

Dao接口

package wang.dao;

public interface DataDao {
public void save();
}

Dao实现

package wang.dao.impl;

import wang.dao.DataDao;

import java.util.*;

public class DataDaoImpl implements DataDao {

private int[] array;

private List<String> list;

private Set<String> set;

private Map<String,String> map;

private Properties properties;




public void setArray(int[] array) {
this.array = array;
}

public void setList(List<String> list) {
this.list = list;
}

public void setSet(Set<String> set) {
this.set = set;
}

public void setMap(Map<String, String> map) {
this.map = map;
}

public void setProperties(Properties properties) {
this.properties = properties;
}




public void save() {
System.out.println("book dao save ...");

System.out.println("遍历数组:" + Arrays.toString(array));

System.out.println("遍历List" + list);

System.out.println("遍历Set" + set);

System.out.println("遍历Map" + map);

System.out.println("遍历Properties" + properties);
}
}

配置文件:

<?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 id="dataDao" class="wang.dao.impl.DataDaoImpl">
<!--数组注入-->
<property name="array">
<array>
<value>100</value>
<value>200</value>
<value>300</value>
</array>
</property>
<!--list集合注入-->
<property name="list">
<list>
<value>java</value>
<value>c++</value>
<value>python</value>
<value>php</value>
</list>
</property>
<!--set集合注入-->
<property name="set">
<set>
<value>java</value>
<value>python</value>
<value>java</value>
<value>php</value>
</set>
</property>
<!--map集合注入-->
<property name="map">
<map>
<entry key="country" value="china"/>
<entry key="province" value="shanxi"/>
<entry key="city" value="xian"/>
</map>
</property>
<!--Properties注入-->
<property name="properties">
<props>
<prop key="country">china</prop>
<prop key="province">shanxi</prop>
<prop key="city">xian</prop>
</props>
</property>
</bean>
</beans>

主函数:

package wang.dao;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App6 {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
DataDao dataDao = (DataDao) ctx.getBean("dataDao");
dataDao.save();
}
}

运行结果:

SSM02-04集合注入

第三方资源注入

容器

两种加载容器的方式

ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); //推荐
ApplicationContext ctx = new FileSystemXmlApplicationContext("D:\\ssm\\ssm\\springtest\\springtest\\src\\main\\resources\\applicationContext.xml")	//绝对路径寻找

两种获取bean的方式

Dao dao = (DataDao) ctx.getBean("dao");
Dao dao = ctx.getBean("dao", Dao.class);  //多个同种类型报错

对比ApplicationContext和BeanFactory

BeanFactory是顶级接口的Bean是延迟加载

ApplicationContext是子接口(常用)也可以延迟加载,在bean中加入参数 lazy-init=“true” 即可

加载第三方Bean

加载Properties文件

步骤如下:

  1. 开启Context命名空间
  2. 使用context加载properties文件
  3. 使用属性占位符${}读取properties配置文件中的属性

样例代码如下:

<?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"
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
">
<!--步骤-->
<!--1.开启命名空间-->
<!--2.使用context加载properties文件-->
<context:property-placeholder location="xxxx.properties"/>

<!--3.使用属性占位符${}读取properties配置文件中的属性-->
<bean class="xxxx">
<property name="xxxx" value="${ 配置中的变量名称 }"/>
</bean>
</beans>

注意:加载时可以关闭系统属性,因为系统属性的优先级高于

注意:多个配置文件用逗号隔开

注意:专业的写法加载所有配置文件如下

<!-- 加载properties文件标准格式 -->
<context:property-placeholder location="classpath:*.properties" system-properties-mode="NEVER"/>
<!-- 从类路径或jar包中搜索并加载properties文件
<context:property-placeholder location="classpath*:*.properties" system-properties-mode="NEVER"/>

总结(来自黑马程序员,侵删)

容器相关

SSM02-05容器相关

bean相关

SSM02-06bean相关

依赖注入相关

SSM02-07依赖注入相关