一、了解Bean
1.什么是Bean
通俗一点来说baen就是java对象,只不过是由容器创建,并且由容器管理对象生命周期。
Bean的本质就是Java中的对象,而Spring中的Bean其实就是对实体类的引用,来生产Java类对象,从而实现生产和管理Bean 。
2.Bean的属性
Bean的配置使用xml配置,XML配置文件的根元素是,中包含了多个子元素,每一个子元素定义了一个Bean,并描述了该Bean如何被装配到Spring容器中。关于元素的常用属性如下表所示:
id :bean 再容器的唯一标识
name: bean 在容器中一个标识name ,namek可以有多个使用,或者; 分割
class:bean 创建时要按照那个类类进行创建
注:id必须是Bean中唯一的,而name可以有多个
3.bean的实例化
在Spring中,要想使用容器中的Bean,也需要实例化Bean。实例化Bean有三种方式:
1.构造器实例化
2. 静态工厂方式实例化
3. 实例工厂方式实例化
(其中最常用的是构造器实例化)
1).默认无参构造方法
容器调用无参构造方法创建对象
2).静态工厂实例化
可以自定创建的对象,并且将对象交给容器管理实现
创建静态工厂
/**
* 静态工厂
*/
public class StaticStudentFactory {
/**
* 自定义 Student 对象的创建
*
* // 获取了创建对象的权力
* @return
*/
public static Student createStudent(){
Student student = new Student();
// 比如name 去网络查询 数据库查询
student.setName("xiaoming");
student.setId(1000);
return student;
}
}
声明使用工厂创建的对象,配置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.xsd">
<!--
bean 像容器声明创建对象 此时创建对象是由静态工厂创建 而不是容器直接创建
class="com.yyf.factory.StaticStudentFactory" 创建对象的静态工厂
factory-method="createStudent" 制定创建对象的静态工厂方法
-->
<bean id="student" class="com.yyf.factory.StaticStudentFactory" factory-method="createStudent">
</bean>
</beans>
测试、获取对象
public class StaticFactoryTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:factory/staticfactory_bean.xml");
Student student = (Student) applicationContext.getBean("student");
System.out.println("student:"+student);
}
}
3).实例工厂实例化
作用和静态工厂实例化一致
总结:静态工厂实例化和是工厂实例化
作用是根据自己定义需求创建对象,主要用于dao层连接的初始(解决MySQL密码加密问题、密码的加密解密问题)
二、Bean的作用域
1.singleton 单例
在配置文件声明bean 在容器只有一个唯一bean ,当每次获取都是同一个bean
singleton
1.在容器启动只创建一个 id 为student 的bean
2.并且放置在容器中,容器管理他的生命周期
2.propertype 原型
当用户向容器获取bean 时,容器才创建,容器只负责创建,不负责保存维护他的生命周期
1.用户向容器获取时 创建id student2对象
2.每次都创建新的对象
3.容器只负责帮我们创建 不会放置在容器中,不会管理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.xsd">
<!--
声明让容器创建一个 Student类型的bean id student1
scope="singleton" 容器创建bean scope 默认的 作用域是单例singleton
singleton 1.在容器启动只创建一个 id 为student1 bean 2.并且放置在容器中,容器管理他的生命周期
-->
<bean id="student1" class="com.yyf.entity.Student" scope="singleton">
<property name="id" value="1000"></property>
<property name="name" value="xiaoming"></property>
</bean>
<!--
声明让容器创建bean 作用域prototype
prototype 1.用户向容器获取时 创建id student2对象 2.每次都创建新的对象 3.容器只负责帮我们创建 不会放置在容器中,不会管理bean 的生命周期 ,由用户自己负责
-->
<bean id="student2" class="com.yyf.entity.Student" scope="prototype">
</bean>
</beans>
测试
public class SingletonTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("scope/singleton_bean.xml");
Student student1_A = (Student) applicationContext.getBean("student1");
System.out.println("student1_A:"+student1_A);
Student student1_B = (Student) applicationContext.getBean("student1");
System.out.println("student1_B:"+student1_B);
System.out.println("student1_A == student1_B:"+(student1_A == student1_B));
System.out.println("***************************************************");
// 获取 原型的student2 当获取时 容器创建
Student student2_A = (Student) applicationContext.getBean("student2");
System.out.println("student2_A:"+student2_A);
// 第二次获取 原型的student2 当获取时 容器创建
Student student2_B = (Student) applicationContext.getBean("student2");
System.out.println("student2_B:"+student2_B);
System.out.println("student2_A== student2_B:"+(student2_A==student2_B));
}
}
3.bean的生命周期
bean 的生命周期
单例的bean:随着容器的启动,bean 创建,容器并负责维护bean的生命周期
原型的bean: 容器启动时不创建bean,当用户获取时容器才创建bean,每次都是新的bean,容器部管理他的生命周期
三、bean的装配
什么是bean的装配
Bean的装配可以理解为依赖关系注入,Bean的装配方式即Bean依赖注入的方式。Spring容器支持多种形式的Bean的装配方式,如基于XML的装配、基于注解(Annotation)的装配和自动装配(其中最常用的是基于注解的装配)
1)基于xml装配
设置值装配
1.必有由无参构造 2.必须有setter方法
构造方法装配
使用setter方法注入,必备条件:**Bean类必须有一个无参构造方法,Bean类必须为属性提供setter方法
1.必须有构造方法 2.使用<constructor-arg 进行初始化
示例
先附上student实体类
public class Student {
private int id;
private String name;
private List<String> courseList ;
public List<String> getCourseList() {
return courseList;
}
public void setCourseList(List<String> courseList) {
this.courseList = courseList;
}
public Student(int id, String name) {
this.id = id;
this.name = name;
}
public Student(int id, String name, List<String> courseList) {
this.id = id;
this.name = name;
this.courseList = courseList;
}
public Student() {
System.out.println("student无参构造被调用");
}
/**
* 初始化方法
*/
public void init(){
System.out.println("name:"+name+"Student-init()");
}
/**
* 销毁方法
*/
public void destroy(){
System.out.println("name:"+name+"Student-destroy()");
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", courseList=" + courseList +
'}';
}
}
dao层有一个studentDao接口 有一个方法为findStudentById用于测试
public interface IStudentDao {
/**
* 更具id 查找student
* @param id
* @return
*/
Student findStudentById(int id);
}
dao.impl层有一个studentDaoImpl实现Dao层接口
@Repository// 标记当前类是dao层
public class IStudentDaoImpl implements IStudentDao {
public Student findStudentById(int id) {
Student student = new Student();
student.setId(id);
student.setName("鞠婧祎");
return student;
}
}
service层 StudentService
public interface StudentService {
/**
* 更具id 查找student
* @param id
* @return
*/
Student findStudentById(int id);
}
service.impl实现层StudentServiceImpl
//@Component // 将当前类 生成对象并加入到 容器
@Service // 继承 @Component 功能
public class StudentServiceImpl implements StudentService {
// 使用注入的注解 注入bean
//@Autowired // 去容器中 根据对应类型 查找对应bean ,并设置到当前 属性中 //如果容器有 多个类型的bean则报错
// @Qualifier("studentDao1") // @Qualifier 与@Autowired 配合 ,当根据类型找到多个时 使用 @Qualifier 按照id 或者name 查找为一个bean
// @Resource // 首先按照 id 为属性名studentDao 去容器中找到对应的bean 2.如果找不到 在按照类型去查找 如果找到多个 报错
//@Resource(name = "studentDao1") // 如果传递 name 则按照 name 为studentDao1 去容器中查找 id 或者name 相同的bean
@Autowired
private IStudentDao studentDao ;
public IStudentDao getStudentDao() {
return studentDao;
}
public void setStudentDao(IStudentDao studentDao) {
this.studentDao = studentDao;
}
public StudentServiceImpl() {
}
public StudentServiceImpl(IStudentDao studentDao) {
this.studentDao = studentDao;
}
public Student findStudentById(int id) {
return studentDao.findStudentById(id);
}
}
xml配置,1.必须有构造方法 2.使用 进行初始化
<?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">
<!--
基于xml setter 装配 设置值 必须由两个条件 :1.有无参构造 2.要有setter 方法 必不可少
-->
<bean id="student1" class="com.qfedu.entity.Student">
<property name="name" value="xiaoming"></property>
<property name="id" value="1000"></property>
<property name="courseList" >
<list>
<value>java</value>
<value>c++</value>
<value>python</value>
</list>
</property>
</bean>
<!--
基于xml 构造方法的装配 初始化
<constructor-arg 给构造参数 传数据
index="0" 下标0 代表第一个参数
value="1001" 第一个参数的值
-->
<bean id="student2" class="com.qfedu.entity.Student">
<constructor-arg index="0" value="1001"></constructor-arg>
<constructor-arg index="1" value="xiaohua"></constructor-arg>
<constructor-arg index="2">
<list>
<value>java</value>
<value>c++</value>
<value>python</value>
</list>
</constructor-arg>
</bean>
<bean id="studentDao" class="com.yyf.dao.impl.IStudentDaoImpl"></bean>
<bean id="studentService" class="com.yyf.service.StudentServiceImpl">
<!--
ref="studentDao" 通过ref 引用id studentDao的bean 进行装配
-->
<property name="studentDao" ref="studentDao">
</property>
</bean>
</beans>
测试
public class XmlTest {
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("xml/settter_bean.xml");
// 按照类型 去获取 Bean 如果容器中只有一个 bean 可以,如果有多个同类型的bean
// 则报错 available: expected single matching bean but found 2: student1,student2
// 容器找到了 两个bean ,但是不确定你需要那一个bean
// 需要你传更确且 name id 来查找
Student student1 = (Student) applicationContext.getBean("student1");
System.out.println("student1:"+student1);
Student student2 = (Student) applicationContext.getBean("student2");
System.out.println("student2:"+student2);
// 获取类型 StudentService.class 实例 bean
StudentService studentService = applicationContext.getBean(StudentService.class);
Student student3 = studentService.findStudentById(2000);
System.out.println("student3:"+student3);
}
}
4.基于注解的装配
基于XML的装配可能会导致XML配置文件过于臃肿,给后续的维护和升级带来一定的困难。为此,Spring提供了对Annotation(注解)技术的全面支持。
1)注入的注解 设置值
@Autowired:去容器中 根据对应类型 查找对应bean ,并设置到当前 属性中 如果容器有 多个类型的bean则报错
@Qualifier(“studentDao1”) : @Qualifier 与@Autowired 配合 ,当根据类型找到多个时 使用 @Qualifier 按照id 或者name 查找为一个bean
@Resource:首先按照 id 为属性名studentDao 去容器中找到对应的bean 2.如果找不到 在按照类型去查找 如果找到多个 报错
@Resource(name = “studentDao1”) 如果传递 name 则按照 name 为studentDao1 去容器中查找 id 或者name 相同的bean
2) 生成bean的注解
这四个注解都是都一个作用生成bean,@Component是其他三个的父类
@Component
@Repository 指明当前实例 是dao 层的实例
@Service 指明当前实例是service 层的实例
@Controller 指明当前实例是控制 层的实例 但是springmvc 中控制层只能用 @Controller
3)半自动注解装配
只能进行注入,使注入的注解生效,bean的生成还需要在xml进行配置*实现是 <context:annotation-config></context:annotation-config>
1.首先在容器中声明bean
2.使用对应注入的注解 注入bean
3.是注入的注解生效
举例
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.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!--
作用就是让 注入的注解生效
-->
<context:annotation-config></context:annotation-config>
<!--1. 声明 bean-->
<bean id="studentDao" class="com.yyf.dao.impl.IStudentDaoImpl"></bean>
<bean id="studentService" class="com.yyf.service.StudentServiceImpl">
</bean>
</beans>
测试
public class StudentServiceImpl implements StudentService {
// 使用注入的注解 注入bean
@Autowired // 去容器中 根据对应类型 查找对应bean ,并设置到当前 属性中
private IStudentDao studentDao ;
public IStudentDao getStudentDao() {
return studentDao;
}
public void setStudentDao(IStudentDao studentDao) {
this.studentDao = studentDao;
}
public Student findStudentById(int id) {
return studentDao.findStudentById(id);
}
}
4).自动注解 context:component-scan
自动注解就是 通过注解自动的生成bean 并经行装配
实现:在xml 声明 context:component-scan 使对应包下的 注入的注解(@Autowired @Qualifie @Resource )生成bean的注解(@Component@Repository @Service @Controller)生效
实现
1.开启自动注解
<?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 https://www.springframework.org/schema/context/spring-context.xsd">
<!--
开启 自动注解功能 使 注入的注解(@Autowired @Qualifie @Resource )生成bean的注解(@Component@Repository @Service @Controller)生效
-->
<context:component-scan base-package="com.yyf"></context:component-scan>
</beans>
2.标记需要 生成 bean 和主要注入的属性
dao层
//@Component("studentDao1") // 将IStudentDaoImpl 生成实例 并加入到容器中 为生成的bean 制定id studentDao1
@Repository // 标记当前类是dao层
public class IStudentDaoImpl implements IStudentDao {
public Student findStudentById(int id) {
Student student = new Student();
student.setId(id);
student.setName("xxxx");
return student;
}
}
service层
//@Component // 将当前类 生成对象并加入到 容器
@Service // 继承 @Component 功能
public class StudentServiceImpl implements StudentService {
// 使用注入的注解 注入bean
// @Autowired // 去容器中 根据对应类型 查找对应bean ,并设置到当前 属性中 //如果容器有 多个类型的bean则报错
// @Qualifier("studentDao1") // @Qualifier 与@Autowired 配合 ,当根据类型找到多个时 使用 @Qualifier 按照id 或者name 查找为一个bean
// @Resource // 首先按照 id 为属性名studentDao 去容器中找到对应的bean 2.如果找不到 在按照类型去查找 如果找到多个 报错
@Resource(name = "studentDao1") // 如果传递 name 则按照 name 为studentDao1 去容器中查找 id 或者name 相同的bean
private IStudentDao studentDao ;
public IStudentDao getStudentDao() {
return studentDao;
}
public void setStudentDao(IStudentDao studentDao) {
this.studentDao = studentDao;
}
public Student findStudentById(int id) {
return studentDao.findStudentById(id);
}
}
测试
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("annotation/auto_bean.xml");
// 获取类型 StudentService.class 实例 bean
StudentService studentService = applicationContext.getBean(StudentService.class);
Student student3 = studentService.findStudentById(2000);
System.out.println("student3:"+student3);
}
5)基于xml 自动装配
所谓自动装配,就是将一个Bean自动的注入到到其他Bean的Property中。 Spring的元素中包含一个autowire属性,我们可以通过设置autowire的属性值来自动装配Bean。autowire属性有5个值.
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.xsd">
<bean id="studentDao" class="com.qfedu.dao.impl.IStudentDaoImpl"></bean>
<bean id="studentDao2" class="com.qfedu.dao.impl.IStudentDaoImpl"></bean>
<!--
基于 xml 自动装配
autowire="byType" StudentServiceImpl 中属性 需要那些bean 就去根据类型去容器查找对应bean
autowire="byName" StudentServiceImpl 根据属性中对应属性名 作为id 去查找 ,如果找不到就不设置对应的属性
autowire="constructor" 1.首先根据类型去类型 去查找,如果找到一个就设置对应bean
2.如果找到两个 则根据参数变量名去查找 根据构造器中对应 参数名作为id 去查找 查找不到就传null
-->
<bean id="studentService" class="com.qfedu.service.StudentServiceImpl" autowire="constructor">
</bean>
</beans>
测试
/**
* xml 自动装配
*/
public class XMLAuto {
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("xml/xml_auto_bean.xml");
// 获取类型 StudentService.class 实例 bean
StudentService studentService = applicationContext.getBean(StudentService.class);
Student student3 = studentService.findStudentById(2000);
System.out.println("student3:"+student3);
}
}