Spring中的Bean
Bean的配置
- spring可以看成一个大型的工厂,这个工厂主要是来生产和管理Spring容器中的Bean,只需要对Spring的配置文件进行配置就可以使用这个工厂。
- Spring容器支持Xml和Properties两种格式的配置文件,常用的是xml,通过配置xml来注册并管理Bean之间的依赖关系。
- 根元素
- 子元素,每一个bean代表一个Bean,并描述了Bean如何装配到Spring容器中。
- @@@@
- id: 每个bean的唯一的表示,Spring容器对Bean的配置,管理通过该属性来完成。
- name: spring容器同样可以通过该容器进行对Bean的配置和管理,name可以对Bean指定多个名称,用逗号隔开。
- class: 指定Bean的具体的实现类
- scope:设定Bean实例的作用域:singleton(单例),prototype(原型)等默认是singleton
- constructor-arg : 元素的子元素,可以使用此元素传入的构造参数进行实例化,该元素的index属性指定构造参数的序号(从0开始),type属性指定构造参数的类型,通过value属性或者ref属性来直接指定,
- property: 元素的子元素 ,用于调用Bean实例中的setter方法来完成属性的赋值,从而完成依赖注入,该元素的name指定Bean实例中的相应的属性名,ref属性或value属性用于指定参数值。
- ref: 上面两个的子元素,也可用于指定指定Bean工厂的某个Bean实例的引用
- value: 上上面两个的子元素,也可用于指定一个常量值。
- lsit:用于封装list或者数组类型的依赖注入
- set:用于封装set类型的依赖注入
- map:用于封装map类型的依赖注入
- entry:
<?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-4.3.xsd">
<!--使用id属性定义bean1,其对应的实现类为com.itheima.Bean1-->
<bean id="bean1" class="com.itheima.Bean1"></bean>
<!--使用name属性bean2,其对应的实现类是com.itherima.Bean2-->
<bean name="bean2"class="com.itheima.Bean2"></bean>
<!--Bean中没有id或者name,class的值就会作为id来使用-->
</beans>
Bean的实例化
在spring容器中,也要实例化Bean,实例化Bean有三种方式,分别是:构造器实例化,静态工厂实例化,实例工厂方式实例化,
构造器实例化
Bean1
package com.yzb.chapter02.example;
/*
* 使用无参构造方法去实例化Bean
* */
public class Bean1 {
}
Test
package com.yzb.chapter02.example;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
String path = "bean1.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(path);
Bean1 bean1 = (Bean1) applicationContext.getBean("bean1");
System.out.println(bean1);
}
}
bean.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
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">
<bean id="bean1" class="com.yzb.chapter02.example.Bean1"></bean>
</beans>
静态工厂方式实例化
- 配置文件中class指定的是工厂实现类的路径,还要制定使用的工厂方法,spring容器不知到使用的是什莫容器。
Bean2
package com.yzb.chapter02.example1;
public class Bean2 {
}
MyBeanFactory
package com.yzb.chapter02.example1;
public class MyBeanFactory {
//使用自己的工厂创建Bean2的实例
public static Bean2 createBean(){
return new Bean2();
}
}
bean2.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
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">
<bean id="bean2" class="com.yzb.chapter02.example1.MyBeanFactory" factory-method="createBean"></bean>
</beans>
Test1
package com.yzb.chapter02.example1;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test1 {
public static void main(String[] args) {
String path = "com/yzb/chapter02/example1/bean2.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(path);
Bean2 bean2 = (Bean2) applicationContext.getBean("bean2");
System.out.println(bean2);
}
}
实例工厂方式实例化
- 在配置文件中class指定不是实例化的类,而是通过factory-bean指定配置的实例工厂,然后使用factory-method方法确定要是的是哪个方法。
Bean3
package com.yzb.chapter02.example2;
public class Bean3 {
}
MyBean3Factory
package com.yzb.chapter02.example2;
public class MyBean3Factory {
public MyBean3Factory() {
System.out.println("bean3工厂实例化中");
}
//常见Bean3实例化的方法
public Bean3 createBean(){
return new Bean3();
}
}
bean3.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
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">
<bean id="myBean3Factory" class="com.yzb.chapter02.example2.MyBean3Factory"/>
<bean id="bean3" factory-bean="myBean3Factory" factory-method="createBean"/>
</beans>
Test3
package com.yzb.chapter02.example2;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test3 {
public static void main(String[] args) {
//指定配置文件
String path = "com/yzb/chapter02/example2/bean3.xml";
//ApplicationContext加载配置文件,并对Bean进行实例化
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(path);
System.out.println(applicationContext.getBean("bean3"));
}
}
Bean的作用域
- 通过Spring容器创建一个Bean实例的时候,还可以指定它的作用域。
- singleton:(单例): 使用singleton定义的Bean实例在spring容器中只有一个实例,就是说无论多少个Bean引用它,始终指向同一个对象
- prototype(原型):每次通过Spring容器获取prototype定义的Bean时,容器都将创建一个新的Bean实例。
- request:再一次Http请求,容器放回Bean的同一个实例,对于不同的HTTP请求则会产生一个新的Bean,而且该Bean仅在当前的HTTP Request内有效
- session:在一次HTTP Session中,容器会返回该Bean的同一个实例,对于不同的Http请求则会产生一个新的Bean,仅在当前的HTTP Session中有效。
- globalSession:在一个全局的HTTP Session中,容器回返回该Bean的同一个实例,仅在使用protlet上下文时有效。
- application:为每个ServletContext对象创建一个实例,仅在Web相关的ApplicationContext中生效。
- websocket :为每个WebSocket对象创建一个实例,仅在Web相关的ApplicationContext中生效。
singleton(单例)作用域
- 只要id与该Bean的id属性相匹配,就会返回同一个Bean的实例。
Bean4
package com.yzb.chapter02.example3;
public class Bean4 {
}
bean4.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
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">
<bean id="bean4" class="com.yzb.chapter02.example3.Bean4"></bean>
</beans>
Test4
package com.yzb.chapter02.example3;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test4 {
public static void main(String[] args) {
//定义配置文件
String path ="com/yzb/chapter02/example3/bean4.xml";
//加载配置文件
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(path);
//输出获得实例
System.out.println(applicationContext.getBean("bean4"));
System.out.println(applicationContext.getBean("bean4"));
}
}
运行结果
- 是同一个对象,所以singleton调用的同一个对象。
prototype(原型)作用域
bean4.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
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">
<bean id="bean4" class="com.yzb.chapter02.example3.Bean4" scope="prototype"></bean>
</beans>
结果
- 创建了一个新的Bean的实例,所以它的位置时不一样的。
Bean的生命周期
- Spring容器可以管理singleton作用域的Bean的生命周期,在这个作用域下,Spring可以清楚的知道Bean何时被创建,何时完成初始化操作,以及销毁操作,
- 对于prototype作用域的Bean对象的时候,Spring容器只负责创建一个新的Bean,之后的操作交给客户端代码完成,Spring容器不在跟踪它的生命周期,对于每一次请求,spring容器都会创建一个新的Bean,但后续的操作不负责。
生命周期过程图
- 根据配置情况调用Bean的无参构造方法或者工厂方法实例化;
- 利用依赖注入完成Bean中的所有的属性的配置注入;
- 如果Bean实现了BeanNameAware接口,则Spring调用Bean的setBeanName()的方法传入当前的id的值;
- 如果Bean实现了BeanFactoryAware接口,则Spring调用Bean的setBeanFactory()的方法传入当前的工厂实例的引用。
- 如果Bean实现了ApplicationContextAware接口,则Spring调用setApplicaitonContext()方法传入当前的ApplicationContext的实例的引用。
- 如果BeanPostProcessor和Bean关联postProcessBeforeInitialization()对Bean进行加工操作,
- 如果Bean实现了initializingBean接口,则Spring将调用afterPropertiesSet()方法,
- 如果在配置文件中通过init-method属性指定初始化的方法,调用该初始化的方法
- 如果BeanPostProcessor和B关联,spring调用该接口的初始化方法postProcessAfterInitialization().这是的Bean,已经可以被应用系统使用了。
- 如果Bean指定了作用域的范围,如果作用域是singleton,将它Spring Ioc缓冲池中,触发Spring对该Bean的生命周期的管理,如果是prototype的作用域,将交给调用者管理生命周期,Spring将不在管理Bean.
- 如果Bean实现了DisposableBean接口,spring容器调用destory()方法将Spring容器中的singleton作用域的Bean销毁,如果在配置文件中通过destory-method属性指定Bean的销毁方法。
Bean的装配
基于XML的装配
- 设置注入(Setter Injection) 和 构造注入(Constructor Injection)
设置注入(Setter Injection)
- 满足条件
- Bean类提供一个默认的无参的构造方法
- Bean类必须为需要注入的属性提供对应的setter方法。
构造注入(constructor Injection)
- 满足条件
- Bean类需要提供一个所有参数的构造方法,
XML装配代码
User
package com.yzb.chapter02.example4;
import java.util.List;
public class User {
private String username;
private Integer password;
private List<String> list;
/*
* 使用构造注入
* 提供所有参数的有参构造方法
* */
public User(String username, Integer password, List<String> list) {
this.username = username;
this.password = password;
this.list = list;
}
/*
* 使用设值注入
* 提供默认的空参构造方法
* 为所有的属性提供setter方法
* */
public User() {
super();
}
public void setUsername(String username) {
this.username = username;
}
public void setPassword(Integer password) {
this.password = password;
}
public void setList(List<String> list) {
this.list = list;
}
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", password=" + password +
", list=" + list +
'}';
}
}
Bean5.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
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">
<!--使用构造注入装配Bean的实例-->
<bean id="user1" class="com.yzb.chapter02.example4.User">
<constructor-arg index="0" value="tome"/>
<constructor-arg index="1" value="123456"/>
<constructor-arg index="2">
<list>
<value>constructorvalue1</value>
<value>constructorvalue2</value>
</list>
</constructor-arg>
</bean>
<!--使用设置注入装配Bean的实例-->
<bean id="user2" class="com.yzb.chapter02.example4.User">
<property name="username" value="tome"></property>
<property name="password" value="23445"></property>
<property name="list">
<list>
<value>setlistvalue1</value>
<value>setlistvalue2</value>
</list>
</property>
</bean>
</beans>
Test5
package com.yzb.chapter02.example4;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test5 {
public static void main(String[] args) {
//定义配置文件的路径
String path ="com/yzb/chapter02/example4/bean5.xml";
//加载配置文件
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(path);
//构造方式输出结果
System.out.println(applicationContext.getBean("user1"));
//设置方式输出结果
System.out.println(applicationContext.getBean("user2"));
}
}
结果
基于Annotation的装配
- 如果Bean过多的话,那末使用xml配置文件将会太过臃肿,所以可以使用注解的技术的支持。
- @Component:仅仅表示一个组件(Bean),可以用在任何的层次,使用时只需要将该注解标注在相应的类的上面即可。
- @Repository:用于将数据访问层(DAO层)的类表示为Spring中的Bean,其功能与@Component相同
- @Service:通常作用在业务层(Service层),用于将业务层的类表示为Spring中 Bean,其功能与@Component相同.
- @Controller:通常作用在控制层(Spring Mvc的Controller),用于将控制层的类表示为Spring的Bean,其功能与@Component相同.
- @Autowired:用于对Bean的属性变量,属性的setter方法以及构造方法进行标注,配合对应的注解处理器完成Bean的自动装配工作,默认按照Bean的类型进行装配。
- @Resource:作用与@ Autowired相同,区别,@Autowired按照Bean的类型装配,@Resource默认按照实例名称进行自动装配,它的属性由name和type,Spring将name解析为Bean的实例名称,type解析为Bean的实例类型,若指定了对应的name或者type,则将按照对应的方式进行装配,若没有指定,则先按照name进行装配,name没找到,则找type进行装配,若也没又找到,则抛出异常。
- @Qualifier:与@Autowired注解配合使用,将默认的Bean类型的装配方式,更改为Bean实例名称的方式装配,实例名称由@Qualifier注解的参数指定。
- 在代码中,主要用到@Repository,@Service,@Controller.
基于Annotation的装配的代码
UserDAO
package com.yzb.chapter02.example5;
public interface UserDao {
public void say();
}
UserDaoImpl
package com.yzb.chapter02.example5;
import org.springframework.stereotype.Repository;
@Repository("userDao")
public class UserDaoImpl implements UserDao {
@Override
public void say() {
System.out.println("userDao ...save.....");
}
}
UserService
package com.yzb.chapter02.example5;
public interface UserService {
public void say();
}
UserServiceImpl
package com.yzb.chapter02.example5;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service("userService")
public class UserServiceImpl implements UserService {
@Resource(name="userDao")
private UserDao userDao;
@Override
public void say() {
userDao.say();
System.out.println("userService ...save....");
}
}
UserController
package com.yzb.chapter02.example5;
public interface UserController {
public void say();
}
UserControllerImpl
package com.yzb.chapter02.example5;
import org.springframework.stereotype.Controller;
import javax.annotation.Resource;
@Controller("userController")
public class UserControllerImpl implements UserController {
@Resource(name = "userService")
private UserService userService;
@Override
public void say() {
userService.say();
System.out.println("userController .... save.....");
}
}
bean6.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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!--使用context的命名控件,在配置文件中开启相应的注解处理器-->
<!--这个元素的时候,还要指定对应的bean-->
<context:annotation-config/>
<!--分别定义三个Bean的实例-->
<bean id="userDao" class="com.yzb.chapter02.example5.UserDaoImpl"></bean>
<bean id="userService" class="com.yzb.chapter02.example5.UserServiceImpl"></bean>
<bean id="userController" class="com.yzb.chapter02.example5.UserControllerImpl"></bean>
</beans>
bean6.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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!--使用context命名空间,通知Spirng扫描指定包下的所有的Bean类,进行注解解析-->
<context:component-scan base-package="com.yzb.chapter02.example5"></context:component-scan>
</beans>
Test6
package com.yzb.chapter02.example5;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test6 {
public static void main(String[] args) {
//设置配置文件的路径
String path = "com/yzb/chapter02/example5/bean6.xml";
//加载配置文件
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(path);
UserController userController = (UserController) applicationContext.getBean("userController");
userController.say();
}
}
结果图
自动装配
- 就是不适用context命名空间的方式,去完成装配,使用Spring中的元素中的autowire属性,
- 自动装配就是将一个Bean自动的注入到其他Bean的property中
@@@ - autowire的五个值
- default:根据的上一级标签的default-autowire属性值确定,
- byname:根据属性的名称进行装配
- byType:根据属性的数据类型进行装配,
- constructor:根据构造函数参数的数据类型进行自动装配
- no:在默认情况下,不适用自动装配。
修改UserserviceImpl和UserControllerImpl文件,在文件中增加类属性的setter方法。
自动装配的配置文件模板
applicaitonContext.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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd">
</beans>
UserserviceImpl
package com.yzb.chapter02.example5;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service("userService")
public class UserServiceImpl implements UserService {
@Resource(name="userDao")
private UserDao userDao;
@Override
public void say() {
userDao.say();
System.out.println("userService ...save....");
}
public void setUserDao(UserDao userDao){
this.userDao = userDao;
}
}
UserControllerImpl
package com.yzb.chapter02.example5;
import org.springframework.stereotype.Controller;
import javax.annotation.Resource;
@Controller("userController")
public class UserControllerImpl implements UserController {
@Resource(name = "userService")
private UserService userService;
@Override
public void say() {
userService.say();
System.out.println("userController .... save.....");
}
public void setUserService(UserService userService){
this.userService = userService;
}
}
bean6.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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!--使用bean元素的autowire进行自动装配-->
<bean id="userDao" class="com.yzb.chapter02.example5.UserDaoImpl"></bean>
<bean id="userService" class="com.yzb.chapter02.example5.UserServiceImpl" autowire="byName"></bean>
<bean id="userController" class="com.yzb.chapter02.example5.UserControllerImpl" autowire="byName"></bean>
</beans>
对于byname的代码的理解
- 在默认的情况下,通常使用ref来装配Bean,但设置了autowire="byName"后,Spring会对userServiceBean中的属性进行寻找,并将属性名称与配置文件中定义的Bean做匹配,由于UserServiceImpl中定义了UserDao的属性以及setter方法,这与配置文件中id为userDao的Bean相匹配的,所以Spring会自动将id为userDao的Bean装配到Id为userService的Bean中。