??在Spring框架中,Bean是核心概念之一,是Spring装配的组件模型。一切实体类都可以配置成一个Bean,进而就可以在任何其他的Bean中使用。一个Bean也可以不是指定的实体类,这就是抽象Bean。
??在Spring中,构成应用程序主干并由Spring IoC容器管理的对象称为bean。bean是一个由Spring IoC容器实例化、组装和管理的对象。
??bean属性和作用:
??id:给对象在容器中提供一个唯一标识。用于获取对象。
??class:指定类的全限定类名。用于反射创建对象。默认情况下调用无参构造函数。
??scope:指定对象的作用范围。在Spring2.0之前,Bean只有两种作用域,即Singleton(单例)和non-Singleton(也称prototype)。Spring2.0以后,增加了session、request和global session三个专用于Web应用程序上下文的Bean。
??同时,<beans…/>元素是Spring配置文件的根元素,<beans…/>元素可以包含多个<bean…/>子元素,每个<bean…/>元素可以定义一个Bean实例。每一个Bean对应Spring容器里的一个Java实例定义Bean时通常需要指定两个属性:Id和Class
??启动 Spring 容器的时候就会创建所有的 bean(单例,可在实体类的无参构造中添加输出方法进行测试)
① 构造器实例化 – 无参构造器
实体类 – Student
public class Student{
public Student(){
System.out.println("实例化");
}
}
配置文件 – spring-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">
<!--使用构造方法实例化:Student s1=new Student ();-->
<bean id="student" class="cn.tj.domain.Student"></bean>
</beans>
测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring-student.xml")
public class StudentTest {
@Autowired
private Student s1;
@Test
public void student_test1(){
System.out.println(s1);
}
}
② FactoryBean 接口实例化
实体类 – Student
public class Student{
public Student(){
System.out.println("实例化");
}
}
实现类 – StudentFactoryBean
// BeanFactory是一个工厂类接口
// 主要用于管理Bean,包括实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。
// 它通常用于从XML配置文件中加载bean定义,并且根据这些定义创建bean实例。
public class CatFactoryBean implements FactoryBean {
@Override
public Student getObject() throws Exception {//返回实体类对象
return new Student();
}
@Override
public Class<?> getObjectType() {
return Student.class;
}
}
配置文件 – spring-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 id="student" class="cn.tj.domain.StudentFactoryBean"></bean>
</beans>
测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring-student.xml")
public class StudentTest {
@Autowired
private Student s1;
@Test
public void student_test1(){
System.out.println(s1);
}
}
??Bean的作用域指的是Bean在Spring整个框架中的生命周期和作用范围。
??① Singleton:单例作用域。该作用域下,Spring容器中只存在一个Bean实例,所有的请求都返回同一个Bean实例。这是Spring的默认选择的作用域,适用于不需要频繁新建和销毁Bean的情况。
??② Prototype:原型作用域。每次请求时都会创建一个新的Bean实例。这种作用域下,Bean的生命周期很长,不易回收,通常需要进行额外的清除处理。
??③ Request:请求作用域。每个HTTP请求都会创建一个新的Bean实例,该Bean实例仅在当前请求内有效。适用于一次HTTP请求和响应的共享Bean。
??④ Session:会话作用域。每个HTTP会话都会创建一个新的Bean实例,该Bean实例仅在当前会话内有效。适用于用户回话的共享Bean,比如记录一个用户的登陆信息。
??⑤ Application:全局作用域。一个Bean定义对应于单个ServletContext的生命周期。适用于Web应用的上下文信息,例如记录一个应用的共享信息。
??⑥ WebSocket:HTTP WebSocket作用域。一个Bean定义对应于单个WebSocket的生命周期。适用于WebSocket的会话中,保存了一个Map结构的头信息,将用来包裹客户端信息头。
??不配置为 singleton,当 scope 为 prototype 时,容器启动不会创建该 bean,在调用getBean方法时才会创建对象
<bean id="" class="" scope="作用域"/>
public class MyDatasource {
public MyDatasource(){
System.out.println("bean创建,调用无参构造执行");
}
public void getConnection(){
System.out.println("创建连接对象执行.....");
}
public void init(){
System.out.println("init初始化对象执行");
}
public void destroy(){
System.out.println("对象销毁执行destroy方法.....");
}
}
<?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">
<!--创建数据源对象 init destroy是初始化与销毁所调用的方法(在实体类中)-->
<bean id="dataSource" class="cn.tj.domain.MyDatasource"
init-method="init" destroy-method="destroy" scope="prototype"></bean>
</beans>
@Test
public void test_bean(){
ClassPathXmlApplicationContext context= new ClassPathXmlApplicationContext("spring-datasource.xml");
MyDatasource dataSource = (MyDatasource) context.getBean("dataSource");
// 获取连接对象
dataSource.getConnection();
// 执行销毁操作
context.close();
}
??正常关闭容器,才会执行 bean 的配置的 destroy-method 方法。若 bean 的 scope 为 prototype 的,则容器只负责创建和初始化,它并不会被 Spring 容器管理(不需要存起来),由用户自己处理。bean 作用域为 prototype 的即使配置了 destroy-method 也不会被调用。
??Spring 创建对象的过程中,将对象依赖属性通过配置设值给该对象。
??① setter 注入(属性注入),该类需提供对应的 setter 方法
??② 构造器注入:类中必须有无参构造和有参构造
实体类
public class Employee{
private String name;
public Employee() {}
public Employee(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
}
测试
public class EmployeeTest {
@Test
public void test() {
User u1 = new User();
// 属性注入
u1.setName("叶凡");
// 构造器注入
User u2 = new User("石昊");
// 注入值可为常量 bean等等
}
}
??常量指基本数据类型及其包装类,String,BigDecimal等,Bean指的是给对象注入值的是容器中的另外一个对象
① 实体类 – Employee
public class Employee {
private String name;
private Integer age;
private String phone;
private Person person;
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", age=" + age +
", phone='" + phone + '\'' +
", person=" + person +
'}';
}
}
② 被注入的实体类 – Person
public class Person {
@Value("李四")
private String name;
public Person(){
System.out.println("无参构造");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void doWork(){
System.out.println(this.name+"要出去玩");
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
'}';
}
}
③ 配置文件 – spring-emp.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">
<!--set注入:注入emp1的关联对象-->
<bean id="person1" class="cn.tj.domain.Person">
<property name="name" value="叶凡"></property>
</bean>
<!--set注入:注入基本数据类型-->
<bean id="emp1" class="cn.tj.domain.Employee">
<property name="name" value="石昊"></property>
<property name="age" value="20"></property>
<property name="phone" value="1332253222"></property>
<!--set注入:注入对象-->
<!--<property name="对象属性名称" ref="容器另外一个 bean 的 id 值"/>-->
<property name="person" ref="person1"></property>
</bean>
<bean id="emp2" class="cn.tj.domain.Employee">
<property name="name" value="塔兹米"></property>
<property name="age" value="17"></property>
<property name="phone" value="1332568222"></property>
<property name="person" ref="person1"></property>
</bean>
</beans>
④ 测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring-emp.xml")
public class EmpTest {
@Autowired
private Employee emp1;
@Test
public void emp_test(){
System.out.println(emp1);
}
}
① dao层
// 接口
public interface EmployeeDao {
}
// 实现类
public class EmployeeDaoImpl implements EmployeeDao{
}
② service层
// 接口
public interface EmployService {
}
// 实现类
public class EmployServiceImpl implements EmployService{
private EmployeeDao employeeDao;
public void setEmployeeDao(EmployeeDao employeeDao) {
this.employeeDao = employeeDao;
}
}
③ xml
<!--dao创建-->
<bean id="employeeDao" class="cn.tj.dao.EmployeeDaoImpl"></bean>
<bean id="employeeDao2" class="cn.tj.dao.EmployeeDaoImpl2"></bean>
<!--service 层 setter 注入 dao-->
<bean id="employeeService" class="cn.tj.service.EmployServiceImpl">
<property name="employeeDao" ref="employeeDao"></property>
</bean>
① 实体类 – Student
public class Student {
private String name;
private Long sn;
private String phone;
private Date birthday;
public Student() {}
public Student(String name, Long sn, String phone, Date birthday) {
this.name = name;
this.sn = sn;
this.phone = phone;
this.birthday = birthday;
}
public Student(String name, Long sn, String phone) {
this.name = name;
this.sn = sn;
this.phone = phone;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", sn=" + sn +
", phone='" + phone + '\'' +
", birthday=" + birthday +
'}';
}
}
② 配置文件 – spring-student.xml
<!--
构造注入
name 实体类的属性名
index 有参构造的参数索引值 从0开始
type 参数的类型
value 设置的属性值
ref 关联引入的bean
-->
<!--构造注入:需要设置的参数和有参构造的形参类型和数量对应-->
<bean id="student1" class="cn.tj.domain.Student">
<constructor-arg value="叶凡" name="name" ></constructor-arg>
<constructor-arg name="sn" value="001"></constructor-arg>
<constructor-arg name="phone" value="13504568169"></constructor-arg>
</bean>
<bean id="student2" class="cn.tj.domain.Student">
<constructor-arg index="0" value="石昊" ></constructor-arg>
<constructor-arg index="1" value="002"></constructor-arg>
<constructor-arg index="2" value="13504568169"></constructor-arg>
</bean>
<bean id="student3" class="cn.tj.domain.Student">
<constructor-arg type="java.lang.String" value="塔兹米" ></constructor-arg>
<constructor-arg type="java.lang.Long" value="003"></constructor-arg>
<constructor-arg type="java.lang.String" value="13504568169"></constructor-arg>
</bean>
<!--创建当前时间-->
<bean id="date" class="java.util.Date"></bean>
<bean id="student4" class="cn.tj.domain.Student">
<constructor-arg type="java.lang.String" value="张起灵" ></constructor-arg>
<constructor-arg type="java.lang.Long" value="003"></constructor-arg>
<constructor-arg type="java.lang.String" value="13422222"></constructor-arg>
<constructor-arg name="birthday" ref="date"></constructor-arg>
</bean>
③ 测试方法
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:spring-student.xml")
public class StudentTest {
// 1 2 3 4 依次注入
@Autowired
private Student student4;
@Test
public void student_tes() {
System.out.println(student4);
}
}
??主要用于 Spring 框架中,用于完成自动装配。它可以被用于成员变量、方法和构造函数上。
??① 可以让 Spring 自动的把属性或字段需要的对象找出来,并注入到属性上或字段上。
??② 可以加在字段或者 setter 方法上面。
??③ 可以同时注入多个对象,一个对象对应一个注解。
??④ 可以注入一些 Spring 内置的重要对象,比如 BeanFactory,ApplicationContext 等。
??⑤ 默认情况下 Autowired 注解必须要能找到对应的对象,否则报错。通过 required=false 来避免这个问题:@Autowired(required=false)。(默认为true表示必须找到该对象否则报错)
??⑥ Autowired 注解寻找 bean 的方式:
????1.首先按照依赖对象的类型找,若找到,就是用 setter 或者字段直接注入。
????2.如果在 Spring 上下文中找到多个匹配的类型,再按照名字去找,若没有匹配报错。
????3.可以通过使用 @Qualifier(“other(bean的id)”) 标签来规定依赖对象按照 bean 的 id 和 类型的组合方式去找。
实体类
public class Teacher{
@Autowired
private Student student ;
@Override
public String toString() {
return "Teacher的学生有[student =" + student + "]";
}
}
配置文件
<bean id="student " class="cn.tj.domain.Dog"/>
<bean id="teacher" class="cn.tj.domain.Person"/>
测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:04.anno.xml")
public class TeacherTest {
@Autowired
private Teacher teacher;
@Test
public void test() {
System.out.println(teacher);
}
}
??@Resource 注解用于在 Java 应用程序中实现依赖注入。它是 Java EE 规范的一部分,并被 Spring 框架广泛使用。使用 @Resource 注解,Spring 容器会在运行时查找匹配的 bean,可以将一个对象注入到另一个对象的字段、构造函数或方法中。这个过程通常由 Spring 容器管理,通过扫描带有特定注解的类和方法来实现。
??① 可以让 Spring 自动的把属性或字段需要的对象找出来,并注入到属性上或字段上。
??② 可以贴在字段或者 setter 方法上面。
??③ 可以注入一些 Spring 内置的重要对象,比如 BeanFactory,ApplicationContext 等。
??④ Resource 注解必须要能找到对应的对象,否则报错。
??⑤ Resource 注解寻找 bean 的方式:
????1.首先按照名字去找,如果找到,就使用 setter 或者字段注入。
????2.若按照名字找不到,再按照类型去找,但如果找到多个匹配类型,报错。
????3.可以直接使用 name 属性指定 bean 的名称(@Resource(name=“”));但若指定的 name,就只能按照 name 去找,若找不到,就不会再按照类型去。
将 Autowired 注解demo 中的 @Autowired 改为 @Resource 即可
??在Spring框架中,@Value注解用于给基本类型的属性赋值。它允许从配置文件(如.properties或.yml文件)中读取值,并注入到属性中。@Value注解可以用于方法上或属性上。
public class Student{
@Value("大黄")
private String name;
@Override
public String toString() {
return "[name=" + name + "]";
}
}
// application.properties文件内容
database.url=jdbc:mysql://localhost:3306/mydb
database.username=root
database.password=secret
// value注入
@Value("${database.url}")
private String databaseUrl;
@Value("${database.username}")
private String databaseUsername;
@Value("${database.password}")
private String databasePassword;
??这样,Spring会在启动时从配置文件中读取相应的值,并将其注入到这些属性中。此外,@Value注解也可以用于表达式语言(SpEL)表达式,用于获取bean的属性或调用bean的方法
@Value("${key}")
private String valueFromProperty;
// 或者
@Value("#{configProperties['key']}")
private String valueFromConfig;
??将标注的类放入spring容器,交给spring管理,四个注解的功能相同,用于标注不同类型的类(不需再配置xml的bean了)
注解 | 说明 |
---|---|
@Repository | 用于标注数据访问组件,即 DAO 实现类上。 |
@Service | 用于标注业务层实现类上。 |
@Controller | 用于标注控制层类上。 |
@Component | 当不是以上的话,可以使用这个注解进行标注。 |
@Component
public class Student{
@Value("大黄")
private String name;
@Override
public String toString() {
return "[name=" + name + "]";
}
}
注解 | 说明 |
---|---|
@Scope | 贴在类上,标明 bean 的作用域,类似bean标签的scope属性 |
@PostConstruct | 贴在方法上,标明 bean 创建完后调用此方法,类似bean标签的init-method属性 |
@PreDestroy | 贴在方法上,标明容器销毁时调用此方法,类似bean标签的destroy-method属性 |
实体类
@Component
@Scope("prototype")
public class MyDataSource {
public MyDataSource() {
System.out.println("bean创建,调用无参构造执行");
}
public void getConnection() {
System.out.println("创建连接对象执行.....");
}
@PostConstruct
public void init() {
System.out.println("init初始化对象执行");
}
@PreDestroy
public void close() {
System.out.println("对象销毁执行destroy方法....");
}
}
测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("spring-datasource.xml")
public class MyDataSourceTest {
@Autowired
private MyDataSource dataSource;
@Test
public void test() {
dataSource.getConnection();
}
}