Bean是一个被实例化,组装,并通过 Spring IoC 容器所管理的对象。为了让Spring IoC容器正确的实例化Bean,需要对Bean实例化的相关信息进行配置。
装配的三种方式
实例化及依赖注入的方法。
1.1 基于XML的显式装配
xml 中 bean 的基本配置结构如下
<?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="..." class="...">
<!-- collaborators and configuration for this bean go here -->
</bean>
<bean id="..." class="...">
<!-- collaborators and configuration for this bean go here -->
</bean>
<!-- more bean definitions go here -->
</beans>
id代表bean的唯一标识,class代表bean的类型
1.1.1 实例化方法:构造方法(常用)、静态工厂和实例工厂
三种实例化方法的XML配置方法:
<!-- 一、使用默认构造函数创建,如果没有该默认构造函数,则创建失败。 -->
<bean id="userService1" class="com.smday.service.impl.UserServiceImpl"></bean>
<!-- 二、使用普通公章中的方法创建对象(使用某个类中的方法创建对象,并存入spring容器 -->
<bean id="instanceFactory" class="com.smday.factory.InstanceFactory"></bean>
<bean id="userService2" factory-bean="instanceFactory" factory-method="getUserService"></bean>
<!-- 三、使用工厂中的静态方法创建对象 -->
<bean id="userService3" class="com.smday.factory.StaticFactory" factory-method="getUserService"></bean>
工厂方法需要对应的工厂类:
//实例工厂方法对应的工厂类
public class InstanceFactory {
public BeanClass getUserService() {
return new BeanClass("实例工厂方法");
}
}
//静态工厂对应的类
public class StaticFactory {
private static BeanClass beanInstance = new BeanClass("调用静态工厂方法实例化Bean");
public static BeanClass createInstance() {
return beanInstance;
}
}
使用时,使用getBean("id")即可,如
BeanClass b = (BeanClass)appCon.getBean("staticFactoryInstance");
1.1.2 依赖注入方法:构造器注入、setter注入
构造器注入:<constructor-arg>标签
需要实例化的Bean定义:
public class ExampleBean {
private AnotherBean beanOne;
private YetAnotherBean beanTwo;
private int i;
public ExampleBean(
AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) {
this.beanOne = anotherBean;
this.beanTwo = yetAnotherBean;
this.i = i;
}
}
在xml中使用构造器注入:
<bean id="exampleBean" class="examples.ExampleBean">
<!-- constructor injection using the nested ref element -->
<constructor-arg>
<ref bean="anotherExampleBean"/>
</constructor-arg>
<!-- constructor injection using the neater ref attribute -->
<constructor-arg ref="yetAnotherBean"/>
<constructor-arg type="int" value="1"/>
</bean>
<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
value:用于提供基本类型和String类型的数据。
ref:用于提供其他的bean类型数据,在spring的ioc核心容器中出现过的bean对象
setter注入:<property>标签
需要实例化的Bean定义,需要提供 set方法
public class ExampleBean {
private AnotherBean beanOne;
private YetAnotherBean beanTwo;
private int i;
public void setBeanOne(AnotherBean beanOne) {
this.beanOne = beanOne;
}
public void setBeanTwo(YetAnotherBean beanTwo) {
this.beanTwo = beanTwo;
}
public void setIntegerProperty(int i) {
this.i = i;
}
}
XML文件
<bean id="exampleBean" class="examples.ExampleBean">
<!-- setter injection using the nested ref element -->
<property name="beanOne">
<ref bean="anotherExampleBean"/>
</property>
<!-- setter injection using the neater ref attribute -->
<property name="beanTwo" ref="yetAnotherBean"/>
<property name="integerProperty" value="1"/>
</bean>
<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
name:指定注入时调用的set方法的属性名称。
value:提供基本类型和String类型的数据。
ref:提供其他的bean类型数据,在spring的ioc核心容器中出现过的bean对象。
集合类型的注入:list和map两类
<bean id="userService" class="com.smday.service.impl.UserServiceImpl">
<property name="myStrs">
<array>
<value>AAA</value>
<value>BBB</value>
<value>BBB</value>
</array>
</property>
<property name="myList">
<list>
<value>AAA</value>
<value>BBB</value>
<value>BBB</value>
</list>
</property>
<property name="mySet">
<set>
<value>AAA</value>
<value>BBB</value>
<value>BBB</value>
</set>
</property>
<property name="myMap">
<map>
<entry key="testA" value="AAA"></entry>
<entry key="testB" >
<value>BBB</value>
</entry>
</map>
</property>
<property name="myProp">
<props>
<prop key="testC">CCC</prop>
<prop key="testD">DDD</prop>
</props>
</property>
</bean>
list结构:使用list、array和set标签
map结构:使用map和props标签
1.2 基于Java的显式装配
嘿嘿,老师没讲不写了
1.3基于注解的自动装配
Spring从以下两个角度实现自动装配:
- 组件扫描:Spring自动发现应用上下文中所创建的bean,即扫描出项目中需要管理的bean并实例化放入缓存池。在bean类前使用注解,并在XML中设置
<context:component-scan base-package="xxx"/>实现。 - 自动装配:Spring自动满足bean之间的依赖,如果一个bean中有其他bean作为成员,可自动在Spring缓存池中寻找对应的bean。在成员属性前添加注解
@Autowired实现。
1.3.1 基本结构
比如Controller层要使用Service层的bean:
定义一个Service层接口
public interface UserService {
void add();
}
定义Service层接口实现类
@Component注解告知Spring创建这个bean,@Component相当于@Component(),或@Component("userServiceImpl"),或@Component(value = "userServiceImpl"),value为Bean的id,默认为首字母小写的类名,可自定义。
@Component
public class UserServiceImpl implements UserService {
@Override
public void add() {
System.out.println("添加用户");
}
}
定义Controller层
@Value注解将外部的值动态注入到Bean (相关博客)
@Autowired注解告诉Spring自动注入Userservice,默认按照Bean类型装配
@Component
public class UserController {
@Value("注入普通字符串")
private String s;
@Autowired
private UserService userservice;
public String getS() {
return s;
}
public void setS(String s) {
this.s = s;
}
public void add(){
System.out.println("s = "+s);
userservice.add();
}
}
在XML中配置注解,指定Spring容器去哪里扫描Bean对象
<?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:tx="http://www.springframework.org/schema/tx"
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/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<context:component-scan base-package="com.service" />
<context:component-scan base-package="com.controller" />
</beans>
测试类
public class Test {
public static void main(String args[]) {
@SuppressWarnings("resource")
ApplicationContext appCon = new ClassPathXmlApplicationContext("applicationContext.xml");
UserController tmp = (UserController) appCon.getBean("userController");
tmp.add();
}
}
1.3.2 常用注解
@Component
-
作用:将当前类对象存入spring容器中。
-
属性:value,用于指定bean的id,不指定value时,默认值为当前类名首字母小写。
-
在三层架构中,Spring框架提供了明确的三层注释,作用与@Component相同,但语义更加清晰,分别是:@Controller:控制层、@Service:业务层、@Respository:数据访问层
@Autowired
-
作用:对类成员变量、方法及构造方法进行标注,完成自动装配的工作。自动按照类型注入,只要容器中有唯一的一个bean对象类型和要注入的变量类型匹配,就可以注入成功。在使用注解注入时,set方法就不是必须的了。
-
如果IoC容器中没有任何bean类型和要注入的变量类型匹配,则报错(可以设置required属性的值为false,如果没找到对应类型的bean,则会出于未装配状态)
-
如果IoC容器中有多个类型匹配时出现歧义,也会报错,可以考虑使用@Qualifier和@Resource注解,参考:Spring解决自动装配歧义性的几种方案
@Resource
-
与@Autowired功能一样。区别在于,该注解默认是按照名称来装配注入的,只有当找不到与名称匹配的Bean才会按照类型来装配注入;
-
@Resource注解有两个属性:name和type。name属性指定Bean实例名称,即按照名称来装配注入;type属性指定Bean类型,即按照Bean的类型进行装配。
@Qualifier
- 当@Autowired注解需要按照名称来装配注入,则需要结合该注解一起使用,Bean的实例名称由@Qualifier注解的参数指定。
Bean的作用域
| 作用域名称 | 描述 |
|---|---|
| singleton | 默认的作用域,使用singleton定义的Bean在Spring容器中只有一个Bean实例。 |
| prototype | Spring容器每次获取prototype定义的Bean,容器都将创建一个新的Bean实例。 |
| request | 在一次HTTP请求中容器将返回一个Bean实例,不同的HTTP请求返回不同的Bean实例。仅在Web Spring应用程序上下文中使用。 |
| session | 在一个HTTP Session中,容器将返回同一个Bean实例。仅在Web Spring应用程序上下文中使用。 |
| application | 为每个ServletContext对象创建一个实例,即同一个应用共享一个Bean实例。仅在Web Spring应用程序上下文中使用。 |
| websocket | 为每个WebSocket对象创建一个Bean实例。仅在Web Spring应用程序上下文中使用。 |
针对不同的装配方法,有不同的作用域定义方法:
- 使用
scope="xxx"在XML文件中设置作用域
<bean id="constructorInstance" class="instance.BeanClass" scope="prototype"/>
- 在类定义时使用
@Scope(xxx)注解
@Component
@Scope("prototype")
public class UserController {
@Autowired
private UserService userservice;
}
测试作用域,可以看到prototype作用域下,每次getBean都会得到新的实例
public class TestController {
@Test
public void testMethod(){
ApplicationContext appCon = new ClassPathXmlApplicationContext("applicationContext.xml");
UserController tmp1 = (UserController) appCon.getBean("userController");
System.out.println(tmp1);//com.controller.UserController@4d14b6c2
UserController tmp2 = (UserController) appCon.getBean("userController");
System.out.println(tmp2);//com.controller.UserController@c05fddc
}
}
Bean的生命周期
调用定制的初始化方法、调用定制的销毁方法分别可以使用属性init-method、destroy-method进行配置。
Bean
package life;
public class BeanLife {
public void initMyself() {
System.out.println(this.getClass().getName() + "执行自定义的初始化方法");
}
public void destroyMyself() {
System.out.println(this.getClass().getName() + "执行自定义的销毁方法");
}
}
XML配置文件
<bean id="beanLife" class="life.BeanLife" init-method="initMyself" destroy-method ="destroyMyself"/>
测试
public static void main(String[] args) {
//初始化Spring容器,加载配置文件
//为了方便演示销毁方法的执行,这里使ClassPathXmlApplicationContext实现类声明容器
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
System.out.println("获得对象前");
BeanLife blife = (BeanLife)ctx.getBean("beanLife");
System.out.println("获得对象后" + blife);
ctx.close();//关闭容器,销毁Bean对象
}
输出