Java阶段二Day15
文章目录
- Java阶段二Day15
- 复习前日知识点
- 对象数据类型注入
- 数组类型注入
- 集合类型的注入
- p命名空间
- 引入外部属性文件
- 基于XML管理bean
- bean的作用域
- bean的生命周期
- 代码演示生命周期
- 后置处理器处理展示
- 基于XML的自动装配
- 基于注解管理bean
- 开启组件扫描
- 使用注解定义Bean
- 属性值注入
- `@Autowired`注入
- `@Resource`注入
- Spring全注解开发
- 面试题
- 描述一下bean的生命周期
复习前日知识点
对象数据类型注入
-
引用外部bean,利用ref属性完成
<bean> <property name = "xxx" ref = "外部bean的id"/> </bean>
-
使用内部bean
<bean> <property name = "xxx"> <bean></bean> </property> </bean>
数组类型注入
使用<array>标签
实现
-
数组中存放普通变量
<property name = "xxx"> <array> <value>yyy</value> <value>zzz</value> </array> </property>
-
数组中存放对象
<property name = "xxx"> <array> <ref bean = "外部bean的id"/> <ref bean = "外部bean的id"/> </array> </property>
集合类型的注入
-
List集合:使用
<list>标签
实现<property name = "xxx"> <list> <value>zzz</value> <ref bean = "外部bean的id"/> </list> </property>
-
Map集合:使用
<map>标签
实现<property name = "xxx"> <map> <entry> <key><value>key1</value></key> <value>yyy</value> </entry> <entry> <key><value>key2</value></key> <ref bean = "外部bean的id"/> </entry> <entry key="" value=""/> </map> </property>
-
引用集合类型bean
-
定义
util
的名称空间xmlns:util="http://www.springframework.org/schema/util"
-
定义相关的
util标签
<util:list id="aaa"> <value>yyy</value> <value>zzz</value> </util:list> <util:map id="bbb"> <entry> <key><value>key1</value></key> <value>yyy</value> </entry> <entry> <key><value>key2</value></key> <ref bean = "外部bean的id"/> </entry> <entry key="" value=""/> </util:map>
-
使用
ref属性
引用<property name = "xxx" ref = "aaa"></property> <property name = "xxx" ref = "bbb"></property>
-
p命名空间
-
定义
p
的名称空间xmlns:p="http://www.springframework.org/schema/p"
-
使用
p
的语法注入<bean id = "xxx" class = "xxx" p:naem = "zzz" p:courseList-ref = "外部id"></bean>
引入外部属性文件
-
定义
context
的名称空间xmlns:context="http://www.springframework.org/schema/context"
-
设置外部文件
xxx.properties
的路径<!-- 引入外部属性文件 --> <context:property-placeholder location="classpath:xxx.properties"></context:property-placeholder>
-
使用
S{变量名}
获取数据并注入<property name="xxx" value="${外部文件中的变量名}"></property>
基于XML管理bean
bean的作用域
-
说明
bean的作用域,是指在交给spring创建bean对象时,可以指定是单实例还是多实例,通过bean标签中的scope属性来指定,默认是单实例。
-
单实例和多实例
-
单实例
单实例(Singleton)是指某个类只能创建唯一的一个实例对象,并且该类提供一个全局的访问点(静态方法)来让外界获取这个实例,常常用在那些只需要一个实例来处理所有任务的场景下,例如配置类或数据库连接池等。
-
多实例
多实例(Multiple Instance)则是指可以在同一个类的定义下,创建多个实例对象。每个对象都是相互独立的,有自己的状态和行为;常常用于需要同时处理多个任务的场景。
-
在Spring中可以通过配置bean标签的scope属性来之地那个bean的作用域范围,具体如下
取值 | 含义 | 创建对象时机 |
---|---|---|
singleton(默认) | 在IoC容器中,这个bean的对象为单实例 | IoC容器初始化时 |
prototype | 这个bean在IoC容器中有多个实例 | 获取bean,即getBEan()时 |
bean的生命周期
-
实例化阶段(bean对象创建)
在这个阶段中,容器会创建一个Bean的实例,并为其分配空间。这个过程可以通过构造方法完成。
-
属性赋值阶段
在实例化完Bean之后,容器会把Bean中的属性值注入到Bean中,这个过程可以通过set方法完成。
-
初始化阶段(bean对象初始化)
在属性注入完成后,容器会对Bean进行一些初始化操作;
- 初始化之前:bean的后置处理器可以接收到bean,此处可以对bean做相关操作。
- 初始化之后:bean的后置处理器可以接收到bean,此处可以对bean做相关操作。
-
使用阶段
初始化完成后,Bean就可以被容器使用了
-
销毁阶段
容器在关闭时会对所有的Bean进行销毁操作,释放资源。
代码演示生命周期
User.java
package com.liner.spring.life;
/**
1. 让spring创建bean对象,并继续属性注入
2. 演示生命周期
2.1 实例化:构造方法打印
2.2 属性赋值:set方法打印
2.3 初始化:定义初始化方法
2.4 使用阶段:getBean() 之后打印测试
2.5 销毁:手动关闭loC容器后,打印测试
*/
public class User {
private String username;
public User(){
System.out.println("1-bean对象实例化,调用无参构造方法");
}
//初始化方法
public void initMethod(){
System.out.println("3-bean对象初始化,调用指定的初始化方法");
}
//销毁方法
public void destoryMethod(){
System.out.println("5-销毁bean对象,调用指定的销毁方法");
}
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
'}';
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
System.out.println("2-通过set方法给bean对象属性赋值");
this.username = username;
}
}
UserTest.java
package com.liner.spring.life;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class UserTest {
@Test
public void test(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean-life.xml");
User user = context.getBean("user", User.class);
System.out.println("使用阶段----4-使用bean阶段");
System.out.println("user = " + user);
//销毁方法
context.close();
}
}
bean-life.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">
<!-- init-method 初始化方法 destroy-method 销毁方法 -->
<bean id="user" class="com.liner.spring.life.User" init-method="initMethod" destroy-method="destoryMethod">
<property name="username" value="张三"/>
</bean>
</beans>
演示结果如下
后置处理器处理展示
实现BeanPostProcessor
接口
MyBeanPost.java
package com.liner.spring.life;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class MyBeanPost implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("3之前,初始化之前执行");
return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("3之后,初始化之后执行");
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
}
}
bean-life.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">
<!-- init-method 初始化方法 destroy-method 销毁方法 -->
<bean id="user" class="com.liner.spring.life.User" init-method="initMethod" destroy-method="destoryMethod">
<property name="username" value="张三"/>
</bean>
<!-- 将后置处理器操作交给 spring-->
<bean id="myBeanPost" class="com.liner.spring.life.MyBeanPost"/>
</beans>
演示结果如下
基于XML的自动装配
自动装配:根据指定的策略,在IoC容器中匹配某一个bean,自动为指定的bean中的所依赖的类类型或者接口类型属性赋值
使用bean标签
的autowire属性
设置自动装配效果
-
byType
:根据类型匹配IoC容器中的某个兼容类型的bean,为属性自动赋值- 如果在IoC中,没有任何一个兼容类型的bean能够为属性赋值,则该属性不装配,默认值为null
- 如果在IoC中,有多个兼容类型的bean能够为属性赋值,则抛出异常
NoUniqueBeanDefinitionException
-
byName
: -
将自动装配的属性名,作为bean的id在IoC容器中匹配相对应的bean进行赋值
基于注解管理bean
从Java5开始,Java增加了对注解(Annotation)的支持,它是代码中的一种特殊标记,可以在编译、类加载和运行时被读取,执行相应的处理。开发人员可以通过注解在不改变原有代码和逻辑的情况下,在源代码中嵌入补充信息。
Spring从2.5版本开始提供了对注解技术的全面支持,我们可以使用注解来实现自动装配,简化Spring的xml配置。
Spring通过注解实现自动装配:
- 引入依赖
- 开启组件扫描
- 使用注解定义Bean
- 依赖注入
开启组件扫描
Spring默认不使用注解装配Bean,因此需要在Spring的xml配置中,通过context:component-scan
元素开启Spring Beans的自动扫描功能。开启此功能后,Spring会自动从扫描指定的包(base-package属性设置)及其子包下的所有类,如果类上使用了@Component
注解,就将该类装配到容器中。
<?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:component-scan base-package="com.liner.spring"/>
</beans>
使用注解定义Bean
Spring提供了以下多个注解,这些注解可以直接标注在java类上,将它们定义成Spring Bean。
注解 | 说明 |
---|---|
@Component | 该注解用于描述Spring中的Bean,它是一个泛化的概念,仅仅标识容器中的一个组件(Bean),并且可以作用在任何层次,例如Service层、Dao层等,使用时只需将该注解标注在相应的类上即可。 |
@Respository | 该注解用于**数据访问层(Dao层)**的类标识为Spring中的Bean,功能与@Component相同。 |
@Service | 该注解通常作用在业务层(Service层),用于将业务层的类标识为Spring中的Bean,其功能与@Component相同。 |
@Controller | 该注解通常作用在控制层(如SpringMVC的Controller),用于将控制层的类标识为Spring中的Bean,其功能与@Component相同。 |
注意:以上四种注解本质上都是创建Java bean
对象,而且创建出来的对象没有区别,只是为了开发方便
属性值注入
@Autowired
注入
单独使用@Autowired注解,默认根据类型装配(byType)
@Autowired注解有一个required属性
,默认值是true,表示在注入的时候要求被注入的Bean必须存在,如果不存在则报错。如果required
属性设置为false,表示注入的Bean存在或者不存在都没关系,存在就注入,不存在也不报错。
package com.liner.spring.autowired.controller;
import com.liner.spring.autowired.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
@Controller
public class UserController {
//方式一:属性注入
@Autowired
private UserService userService;
//方式二:set方法注入
@Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
//方式三:构造方法注入
@Autowired
public UserController(UserService userService) {
this.userService = userService;
}
//方式四:形参注入 --很少使用
public UserController(@Autowired UserService userService) {
this.userService = userService;
}
//方式五:只有一个构造函数,可无注解
public UserController(UserService userService) {
this.userService = userService;
}
public void con(){
System.out.println("controller正在运行...");
userService.serv();
}
}
注意:@Autowired注解
根据byType
定位,所以如果一个接口有多个实现类时,会报错
可配合@Qualifier注解
一起使用,指定具体的实现类
@Resource
注入
@Resource注解
也可以完成属性注入,它和@Autowired注解
的区别如下:
@Resource注解
是JDK扩展包中的,也就是说属于JDK的一部分。所以该解释是标准注解,更加具有通用性,而@Autowired注解
是Spring框架自己的@Resource注解
默认根据名称装配byName
,未指定name时,使用属性名作为name,通过name找不到的话会自动启动通过类型byType
装配。而@Autowired注解
默认根据类型装配byType
,如果想根据名称匹配,需要配合@Qualifier注解
一起使用@Resource注解
用在属性上、setter方法上@Autowired注解
用在属性上、setter方法上、构造方法上、构造方法参数上
Spring全注解开发
全注解开发就是不再使用spring配置文件了,写一个配置类来代替配置文件,使用@Configuration注解
标记为配置类
SpringConfig.java
package com.liner.spring.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
//声明此类为配置类
@Configuration
//开启组件扫描
@ComponentScan("com.liner.spring")
public class SpringConfig {
}
面试题
描述一下bean的生命周期
- 第一步实例化,spring调用构造方法对bean实例化,分配出空间资源
- 第二步属性值的注入,调用setter方法对属性值进行注入
- 第三步初始化,可以调用指定的初始化方法进行前置操作,比如数据校验
- 第四步使用阶段,正常使用
- 第五步销毁,当应用程序停止时,Bean对象会销毁释放计算机资源,同时调用指定的销毁方法
- 后置处理器在对象初始化之前可拿到当前对象做一些操作处理,在初始化之后也可以做一些处理