BeanFactory和ApplicationContext区别
BeanFactory是Spring框架的中IOC容器的顶层接口,它只是用来定义一些基础功能和一些基础规范,ApplicationContext是它的子接口,所以ApplicationContext具备BeanFactory提供的全部功能的。通常我们称BeanFactory为Spring IOC的基础容器,ApplicationContext是容器的高级接口,比BeanFactory要拥有更多的功能,比如国际化支持和资源访问等(xml,Java配置类)等等。
启动IOC容器
Java环境下启动IOC容器
- ClassPathXMLApplicationContext: 从类的更路径下架子配置文件(推荐使用)
- FileSystemXMlApplicationContext: 从磁盘路劲上加载配置文件
AnnotationConfigApplicationContext: 纯注解模式下启动Spring容器
// 通过读取classpath下的xml文件来启动容器(xml模式SE应用下推荐)
ClassPathXmlApplicationContext applicationContext = new
ClassPathXmlApplicationContext("classpath:applicationContext.xml");
// 不推荐使用
//ApplicationContext applicationContext1 = new
FileSystemXmlApplicationContext("文件系统的绝对路径");
// 第一次getBean该对象
Object accountPojo = applicationContext.getBean("accountPojo");
Web环境下启动IOC容器
从XML启动容器
<!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>
<!--配置Spring ioc容器的配置⽂件-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!--使⽤监听器启动Spring的IOC容器-->
<listener>
<listenerclass>org.springframework.web.context.ContextLoaderListener</listenerclass>
</listener>
</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的方式
⽅式⼀:使⽤⽆参构造函数
在默认情况下,它会通过反射调⽤⽆参构造函数来创建对象。如果类中没有⽆参构造函数,将创建失败。
<!--配置service对象-->
<bean id="userService" class="com.lagou.service.impl.TransferServiceImpl">
</bean>
- 方式二: 使用静态方法创建
```
public class CreateBeanFactory {
public static ConnectionUtils getInstanceStatic() {
} }return new ConnectionUtils();
```
<bean id="connectionUtils" class="com.lagou.edu.factory.CreateBeanFactory"
factory-method="getInstanceStatic"/>
方法三:实例化方法
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"/>
.通过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>