目录
1.将bean交给spring容器管理
1. 编写bean对象
2. 在resources目录下创建spring config xml文件,并管理bean对象
3. spring容器管理工厂
2.Spring Bean 生命周期
2.1 Spring Bean初始化方法
2.1.1 自定义初始化方法
2.1.2 实现接口(InitializingBean)初始化方法
2.2 Spring Bean 销毁方法
2.2.1 自定义方式销毁
2.2.2 实现DisposableBean接口方式
2.3 Spring Bean 后置处理器
2.3.1 创建一个类(Myprocessor)并实现BeanPoscessor接口
2.3.2 创建一个类(StudentService),并实现InitializingBean接口,使用初始化方法
2.3.3 编写spring配置文件(applicationContext.xml),配置后置处理器,并管理StudentService
2.3.4 最后执行结果
3.Ico(控制反转)
3.1 依赖注入bean的两种方式
3.1.1通过构造的方式注入
3.1.2 通过setter方式注入
3.2 依赖注入注入值
3.2.1 通过构造方式注入属性
3.2.2 通过setter方式注入属性
编辑 3.2.3 注入map属性
3.2.4 注入list属性
4. 注解
4.1 @Component注解
4.2 MVC三大注解(@Controller、@Service、@Repository)
4.3 @Scope注解
4.4 生命周期注解(@PostConstruct、@PoreDestory)
4.4.1 在pom文件中配置javax依赖
4.4.2 @PostConstruct注解(bean初始化)
4.4.3 @PreDestory注解(bean销毁)
4.5 依赖注入注解(@Inject、@Named)
4.6@Resource注解
4.7 @Autowired注解、@Qualifier
4.8 @RequiredArgsConstructor 注解
1.将bean交给spring容器管理
1.为什么要将bean交给spring容器管理?
在没有spring之前,我们需要某个对象时,是通过手动new创建出来对象的,这样手动创建出来的方式具有强耦合的关系,如果在bean对象中需要依赖另一个bean对象时,当被依赖的对象需要做出改变时,需要依赖对象的一方则也要做出想对应的改变
比如 如果被依赖的一方改了名称,则需要依赖的一方也要更改,则间接违反了开闭原则
现在将bean对象交给spring容器管理,则不需要我们手动创建bean对象,Spring容器负责自动创建和注入这些依赖,这就实现了spring中的思想控制反转
所谓控制反转,就是对象不再主动获取依赖(例如通过
new
关键字创建依赖对象),而是由外部容器负责注入依赖给它。当需要对象时,通过容器取获取即可
1. 编写bean对象
1.1 编写UserService接口
public interface UserService {
/**
* 添加用户
*/
void addUser();
}
1.2 编写类对象实现UserService接口
public class UserServiceImpl implements UserService {
@Override
public void addUser() {
System.out.println("添加用户");
}
}
public class TeacherServiceImpl implements UserService {
@Override
public void addUser() {
System.out.println("创建老师");
}
}
2. 在resources目录下创建spring config xml文件,并管理bean对象
定义名为beans.xml的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">
<!--装配UserService实现类-->
<!--id表示这个bean在容器里面的唯一表示-->
<!--class表示bean的完整类名-->
<bean id="userService" class="com.xr.springdemo.service.impl.UserServiceImpl"/>
<bean id="studentService" class="com.xr.springdemo.service.impl.TeacherServiceImpl"/>
</beans>
现在我们创建的bean对象都以及交给spring容器管理了
2.1 通过配置文件初始化容器工厂,并通过工厂来获取bean对象
创建一个main方法
public class Main {
public static void main(String[] args) throws BeansException {
// 根据配置文件初始化一个容器工厂,并关联xml文件
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
// 从容器中获取bean对象(根据xml文件配置bean中的唯一id来获取)
UserService userService = (UserService) context.getBean("userService");
UserService teacherService = (UserService) context.getBean("teacherService");
// 调用
userService.addUser();
teacherService.addUser();
}
}
最后执行结果
现在我们获取bean对象的方式并不是通过new的方式,而是通过spring容器获取到的bean对象
3. spring容器管理工厂
spring容器不仅可以管理bean对象,还可以将自定义工厂交给spring容器管理,而定义工厂生产出来的bean对象也会被spring容器管理,所以spring容器非常灵活
3.1 创建自定义静态工厂 (StudentServiceFactory)
/**
* 自定义工厂来创建特定的对象
* 这个自定义工厂也将纳入spring容器中
* spring会调用自定义工厂的方法来创建Bean对象
* 创建出来的bean也会纳入容器中管理
*/
public class StudentServiceFactory {
public static UserService create() {
return new StudentServiceImpl();
}
}
3.2 将自定义静态工厂交给spring容器管理,而自定义工厂创建出来的bean对象也会被spring容器管理
<?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">
<!--装配UserService实现类-->
<!--id表示这个bean在容器里面的唯一表示-->
<!--class表示bean的完整类名-->
<bean id="userService" class="com.xr.springdemo.service.impl.UserServiceImpl"/>
<bean id="studentService" class="com.xr.springdemo.service.impl.TeacherServiceImpl"/>
<!--装配自定义工厂,由spring容器来管理这个工厂,factory-method指定自定义静态工厂的方法-->
<bean id="studentService" class="com.xr.springdemo.factory.StudentServiceFactory" factory-method="create"/>
</beans>
3.3 通过自定义工厂获取Bean对象
public class Main {
public static void main(String[] args) throws BeansException {
// 根据配置文件初始化一个容器工厂,并关联xml文件
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
// 通过自定义工厂创建的bean对象,并获取
UserService studentService = (UserService) context.getBean("studentService");
// 调用方法
studentService.addUser();
}
}
最后执行结果
发现spring容器将自定义工厂创建出来的bean对象也管理了起来
3.4 基于spring提供的FactoryBean接口创建工厂,官方推荐
/**
* 自定义工厂,这个工厂是实现spring提供的FactoryBean接口
*/
public class TeacherServiceFactoryBean implements FactoryBean<UserService> {
/**
* getObject方法创建一个对象
*/
@Override
public UserService getObject() throws Exception {
return new TeacherServiceImpl();
}
/**
* getObjectType方法返回创建对象的类型
*/
@Override
public Class<?> getObjectType() {
return TeacherServiceImpl.class;
}
}
3.5 创建TeacherServiceImpl类并实现UserService
public class TeacherServiceImpl implements UserService {
@Override
public void addUser() {
System.out.println("创建老师");
}
}
3.6 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">
<!--装配UserService实现类-->
<!--id表示这个bean在容器里面的唯一表示-->
<!--class表示bean的完整类名-->
<bean id="userService" class="com.xr.springdemo.service.impl.UserServiceImpl"/>
<bean id="studentService" class="com.xr.springdemo.service.impl.TeacherServiceImpl"/>
<!--装配自定义工厂,由spring容器来管理这个工厂,factory-method指定自定义静态工厂的方法-->
<bean id="studentService" class="com.xr.springdemo.factory.StudentServiceFactory" factory-method="create"/>
<!--装配实现Spring提供FactoryBean接口的工厂-->
<bean id="teacherService" class="com.xr.springdemo.factory.TeacherServiceFactoryBean"/>
</beans>
3.6 获取bean对象并执行
public class Main {
public static void main(String[] args) throws BeansException {
// 根据配置文件初始化一个容器工厂
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
UserService teacherService = (UserService) context.getBean("teacherService");
teacherService.addUser();
}
}
最后执行结果
这种方式是通过spring提供factoryBean接口的方式创建的工厂并交给spring容器进行管理
2.Spring Bean 生命周期
对象构造方法
- Spring 通过反射机制调用 Bean 的构造方法,创建 Bean 的实例。此时,Bean 还没有完成属性的注入。
- 例如:
new UserService()
,调用无参构造器。后置处理器的
postProcessBeforeInitialization
方法
- 在 Bean 初始化之前,Spring 调用实现了
BeanPostProcessor
接口的后置处理器的postProcessBeforeInitialization
方法。- 这个方法可以对 Bean 进行预处理,在 Bean 完成初始化前做一些自定义操作。
- 对应配置中的
<bean id="myProcessor" class="com.xr.processor.MyProcessor"/>
。InitializingBean 接口的
afterPropertiesSet
方法
- 如果 Bean 实现了
InitializingBean
接口,Spring 会调用其afterPropertiesSet
方法进行初始化操作。- 这个方法是 Spring 内置的初始化回调机制之一,用于在所有的属性被设置后执行一些定制的初始化逻辑。
自定义的
init-method
初始化方法
- 如果在 XML 配置中指定了
init-method
属性,Spring 会调用指定的初始化方法。在配置中,UserService
Bean 使用了beanInit
作为自定义初始化方法。- 这是另一种初始化 Bean 的方式。
后置处理器的
postProcessAfterInitialization
方法
- 在 Bean 初始化之后,Spring 调用实现了
BeanPostProcessor
接口的后置处理器的postProcessAfterInitialization
方法。- 这个方法可以对 Bean 进行后处理操作,在 Bean 初始化完成后做进一步定制化处理。
DisposableBean 接口的
destroy
方法
- 如果 Bean 实现了
DisposableBean
接口,Spring 在销毁 Bean 时会调用其destroy
方法。- 这个方法是 Spring 提供的内置销毁回调,用于 Bean 在被销毁之前执行清理操作。
自定义的
destroy-method
销毁方法
- 如果在 XML 配置中指定了
destroy-method
属性,Spring 在 Bean 被销毁时会调用这个方法。在配置中,UserService
Bean 使用了beanDestroy
作为自定义销毁方法。- 这是另一种销毁 Bean 的方式。
spring Bean先销毁,在着是spring容器销毁
后置处理器(BeanPostProcessor) 是 Spring 框架中一个重要的扩展机制,它允许在 Spring 容器实例化 Bean 之后、初始化方法执行前后对容器中所有 Bean 进行一些自定义的修改或增强。
执行顺序:
bean对象的构造方法--------------------》》》后置处理器
postProcessBeforeInitialization---------------》》》
InitializingBean 接口的afterPropertiesSet
bean初始化方法---------------------》》》自定义的init-method
初始化方法----------------------------------》》》后置处理器的postProcessAfterInitialization
方法-----------------------------》》》DisposableBean 接口的destroy
销毁方法----------------------》》》自定义的destroy-method
销毁方法
初始化方法和销毁方法有两种一个是实现接口,一个是自定义方法,如果两种同时使用,优先执行实现接口的方法,在执行自定义方法
2.1 Spring Bean初始化方法
2.1.1 自定义初始化方法
2.1.1.1 创建UserService类,并编写构造方法和自定义初始化方法
public class UserService {
/**
* 构造方法是被JVM在创建类实例的时候自动调用
* 例如:new UserService();
* 或者基于反射创建 USerService.class.newInstance();
*/
public UserService() {
System.out.println("执行UserService构造方法");
}
/**
* 自定义Bean的初始化方法
*/
public void beanInit() {
System.out.println("执行Bean的初始化方法");
}
}
2.1.1.2 将UserService Bean交给spring容器 管理,编写名为applicationContext.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初始化方法:
两种方式:
第一种方式. 在Bean中自定义初始化方法,在配置中使用init-method属性来指定初始化方法-->
<bean id="userService" class="com.xr.service.UserService" init-method="beanInit"/>
</beans>
在自定义初始化方式,将Bean交给spring 容器管理的时候需要使用init-method属性来指定初始化方法
2.1.1.3 编写Main方法
public class Main {
public static void main(String[] args) {
// 创建spring上下文,从而通过它来访问和操作在Spring配置文件(applicationContext.xml)中定义的bean对象
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
}
}
执行结果:
Main方法 中只是获取了spring上下文,没有调用构造方法和自定义初始化方法,执行的结果却调用了先执行了构造方法在执行自定义初始化方法
构造方法: 由jvm创建
初始化方法: 由spring容器创建
所有Bean对象一开始都是交由spring容器进行管理,所以只要spring容器一开始则就会调用所有bean对象的初始化方法,而构造方法确实jvm创建
2.1.2 实现接口(InitializingBean)初始化方法
2.1.2.1 创建StudenttService类,并实现InitializingBean接口
public class StudentService implements InitializingBean {
public StudentService() {
System.out.println("执行StudentService的构造方法");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("实现了initializingBean接口,执行studnetafterPropertiesSet方法");
}
}
2.1.2.2 将StudentService Bean交给spring容器 管理,在applicationContext.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初始化方法:
两种方式:
第二种方式. 在Bean中实现InitializingBean接口,接口中包含一个afterPropertiesSet方法-->
<bean id="userService" class="com.xr.service.UserService"/>
</beans>
2.1.2.3 编写Main方法
public class Main {
public static void main(String[] args) {
// 创建spring上下文,从而通过它来访问和操作在Spring配置文件(applicationContext.xml)中定义的bean对象
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
}
}
2.1.2.4 执行结果
2.2 Spring Bean 销毁方法
有初始化那么就肯定有销毁,那么spring Bean销毁的方式有两种
1. 自定义销毁方式
2. 实现DisposableBean接口的方式
2.2.1 自定义方式销毁
2.2.1.1 创建一个UserService类,并编写一个销毁bean方法
public class UserService implements DisposableBean {
/**
* 自定义销毁方法
*/
public void beanDestroy() {
System.out.println("准备销毁Bean");
}
}
2.2.1.2 在spring配置文件中(applicationContext.xml)装配该bean对象,并使用destory-method属性指定销毁方法的名称
<?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的第一种销毁方法:
1. 在Bean方法中自定义销毁方法,在配置中使用destroy-method属性来指定销毁方法
-->
<bean id="userService" class="com.xr.service.UserService" destroy-method="beanDestroy"/>
</beans>
2.2.1.3 编写Main方法
public class Main {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
/**
* 关闭容器,关闭才勾起相关的销毁方法
* 如果不关闭容器,那么销毁方法是不会执行的
* 关闭容器之前,bean的销毁方法比关闭容器先执行,bean销毁完成之后容器才会关闭
*/
((ClassPathXmlApplicationContext)context).close();
}
}
2.2.1.4 最后执行结果为
2.2.2 实现DisposableBean接口方式
2.2.2.1 定义StudentService类实现DisposableBean接口,并重写destory方法
public class StudentService implements DisposableBean{
@Override
public void destory() thorw Exception() {
System.out.println("实现类DisposableBean接口,并重写了销毁方法,执行销毁");
}
}
2.2.2.2 在spring配置文件中(applicationContext.xml)装配该bean对象,无需使用destory-method属性指定销毁方法的名称
<?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的第二种销毁方法:
1. 在Bean中实现DisposableBean接口,接口中包含一个destroy方法
-->
<bean id="userService" class="com.xr.service.UserService"/>
</beans>
2.2.2.3 编写main方法
public class Main {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
/**
* 关闭容器,关闭才勾起相关的销毁方法
* 如果不关闭容器,那么销毁方法是不会执行的
* 关闭容器之前,bean的销毁方法比关闭容器先执行,bean销毁完成之后容器才会关闭
*/
((ClassPathXmlApplicationContext)context).close();
}
}
2.2.2.4执行结果为:
如果实现接口的方式和自定义的方式同时使用,优先执行实现接口的方式
2.3 Spring Bean 后置处理器
它是一种允许在 Spring 容器中创建 Bean(Java 对象)之前或之后对 Bean 进行额外处理的接口。Spring 框架利用后置处理器来实现各种功能,比如为 Bean 进行自动注入、代理增强等操作
简要的说:
就是在bean初始化之前和初始化之后可以做一些事情
2.3.1 创建一个类(Myprocessor)并实现BeanPoscessor接口
/**
* Bean的后置处理器(必须实现BeanPostProcessor)
* 后置处理器可以将spring容器装配完Bean之后(包括依赖注入)
* 在执行Bean的初始化方法之前执行(afterPropertiesSet、init-method)前后执行
* 也就是在初始化方法前执行后置处理器的postProcessBeforeInitialization方法
* 在初始化方法后执行后置处理器的postProcessAfterInitialization方法
*/
public class MyProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("执行后置处理器postProcessBeforeInitialization方法,在所有Bean的初始化之前执行,每个bean初始化之前都会执行");
return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("执行后置处理器postProcessAfterInitialization方法,在所有Bean的初始化之后执行,每个bean初始化之后都会执行");
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
}
}
2.3.2 创建一个类(StudentService),并实现InitializingBean接口,使用初始化方法
public class StudentService implements InitializingBean {
public StudentService() {
System.out.println("执行StudentService的构造方法");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("bean的初始化,实现了initializingBean接口,执行studnetafterPropertiesSet方法");
}
}
2.3.3 编写spring配置文件(applicationContext.xml),配置后置处理器,并管理StudentService
<?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对象-->
<bean id="studentService" class="com.xr.service.StudentService" />
<!--装配后置处理器-->
<bean id="myProcessor" class="com.xr.processor.MyProcessor"/>
</bean>
2.3.4 最后执行结果
3.Ico(控制反转)
不是什么技术,而是一种设计思想。在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。
什么是控制反转:
容器将底层模板反向注入到高层模块的过程,间接实现了依赖倒置原则
一开始我们需要某对象都是使用new关键字获取的,现在我们是通过spring容器获取
3.1 依赖注入bean的两种方式
3.1.1.2 先创建controller,service包,并在controller包下创建UserController,在到service创建userService接口和一个子包impl,最后到impl下创建UserServiceImpl并实现userService接口
当我想使用UserServsice实现类的时候,通常时直接在UserController类中创建出来
如:
UserService userService = new UserServiceImpl();
但是我们现在通过容器取获取,将创建对象的主动权交给容器取做,我们直接获取就ok了
UserService接口
public interface UserService {
void add ();
}
UserServiceImpl类实现UserService接口
public class UserServiceImpl implements UserService {
@Override
public void add() {
System.out.println("添加用户");
}
}
3.1.1通过构造的方式注入
通过依赖注入获取bean的第一中方式
UserController类
public class UserController {
/**
* 需要依赖的UserService接口
*/
private UserService userService;
/**
* 1. 方式一通过构造器的方式获取bean对象
* 2.将UserService的实现类注入进来
*/
public UserController(UserService userService) {
this.userService = userService;
}
// 调用userService接口实现的add方法
public void add() {
userService.add();
}
}
spring配置(applicationContext.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">
<!--将userService注入到userController中,通过构造方法注入-->
<!--
name对应构造方法的参数名称,
type指定参数的类型,
index指定参数的下标
所以name、type、index三者都可以指定参数的方式
ref同样是引用容器中Bean的id,
这里我们需要在userController对象中注入的对象是下面的userService
这些都是constructor-arg标签的属性,都是用来指定依赖的bean对象的,选一即可
-->
<!--首先将两个bean对象都交给spring容器管理(userController,userService)-->
<bean id="userController" class="com.xr.controller.UserController">
<!--将下面的userService对象注入到userController中-->
<constructor-arg ref="userService"/>
</bean>
<bean id="userService" class="com.xxr.service.impl.userService"/>
</beans>
编写mian方法
public class Main {
public static void main(String[] args) {
// 容器将低层模板反向注入到高层模块的过程
ApplicationContext application = new ClassPathXmlApplicationContext("applicationContext.xml");
UserController bean = application.getBean(UserController.class);
bean.add();
}
}
最后执行结果
发现:
我们在userController中并没有使用new关键字创建出userService对象,而是通过构造器的方式结合spring的xml配置文件配置来获取的bean对象
3.1.2 通过setter方式注入
userController类
/**
* 通过setter注入
* 通过构造器注入
*/
public class UserController {
private UserService userService;
/**
* 将UserService的实现类注入进来
*/
public void setUserService(UserService userService) {
this.userService = userService;
}
public void add() {
userService.add();
}
}
spring配置(applicationContext.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">
<!--将userService注入到userController中,通过构造方法注入-->
<!--
name对应构造方法的参数名称,
type指定参数的类型,
index指定参数的下标
所以name、type、index三者都可以指定参数的方式
ref同样是引用容器中Bean的id
-->
<bean id="userController" class="com.xr.controller.UserController">
<!--name对应的是set注入方法,将set去掉然后将set后面的第一个字母改成小写,
ref属性值表示引用容器中bean的id,就是你要依赖哪个对象就引用谁的bean-->
<property name="userService" ref="userService"/>
</bean>
<bean id="userService" class="com.xr.service.impl.UserServiceImpl"/>
</beans>
编写main方法
public class Main {
public static void main(String[] args) {
// 容器将低层模板反向注入到高层模块的过程
ApplicationContext application = new ClassPathXmlApplicationContext("applicationContext.xml");
UserController bean = application.getBean(UserController.class);
bean.add();
}
}
执行结果
构造注入和setter方法注入都可以获取想要的依赖,二选一即可
3.2 依赖注入注入值
spring不仅可以注入对象依赖还可以注入属性
3.2.1 通过构造方式注入属性
创建一个UserService类,并定义两个属性(name,age)通过构造方法的方式注入
public class UserService {
/**
* 定义两个属性
*/
private String name;
private Integer age;
/**
* 定义有参构造方法
*/
public UserService(String name,Integer age)
{
this.name = name;
this.age = age;
}
/**
* 最后输出属性
*/
public void say() {
System.out.println("name:"+name+" age:"+age);
}
}
编写spring配置文件(applicationContext.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="userService" class="com.xr.service.UserService">
<!--name指定的是属性的名称,value是属性的值-->
<constructor-arg name="name" value="张三"/>
<constructor-arg name="age" value="18"/>
</bean>
</beans>
编写mian方法
public class Main {
public static void main(String[] args) {
ApplicationContext application = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService bean = application.getBean(UserService.class);
// 调用输出方法
bean.say();
}
}
最后执行结果
3.2.2 通过setter方式注入属性
编写userService类
package com.xr.service;
import java.util.List;
public class UserService {
// 定义两个属性
private String name;
private Integer age;
// 定义set方法
public void setName(String name) {
this.name = name;
}
public void setAge(Integer age) {
this.age = age;
}
// 输出方法
public void say() {
System.out.println("name:"+name+" age:"+age);
}
}
编写spring配置文件(applicationContext.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="userService" class="com.xr.service.UserService">
<property name="name" value="小明"/>
<property name="age" value="18"/>
</bean>
</beans>
编写main方法
public class Main {
public static void main(String[] args) {
ApplicationContext application = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService bean = application.getBean(UserService.class);
// 调用输出方法
bean.say();
}
}
最后执行结果
3.2.3 注入map属性
编写userService类
public class UserService {
private Map<String, String> addresses;
//方式一:通过构造方式注入
public UserService(Map<String,String> addresses) {
this.addresses = addresses;
}
// 方式二:通过set方法注入
public void setAddresses(Map<String, String> addresses) {
this.addresses = addresses;
}
// 最后输出语句
public void say() {
System.out.println(addresses);
}
/*两种方式二选一即可*/
}
编写spring配置文件(applicationContext.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="userService" class="com.xr.service.UserService">
<!--两种方式二选一即可-->
<!--通过构造注入map方法-->
<constructor-arg>
<map>
<entry key="1" value="北京"/>
<entry key="2" value="上海"/>
</map>
</constructor-arg>
<!--通过set 注入map方法-->
<property name="addresses">
<map>
<entry key="1" value="北京"/>
<entry key="2" value="上海"/>
</map>
</property>
</bean>
</beans>
编写main方法
public class Main {
public static void main(String[] args) {
ApplicationContext application = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService bean = application.getBean(UserService.class);
// 调用输出方法
bean.say();
}
}
最后执行结果
3.2.4 注入list属性
编写userService类
package com.xr.service;
import java.util.List;
public class UserService {
// 定义list集合
private List<String> addresses;
// 方式一:通过构造方式注入
public UserService(List<String> addresses) {
this.addresses= addresses;
}
// 方式二: 通过set方式注入
public void setAddresses(List<String> addresses) {
this.addresses = addresses;
}
public void say() {
System.out.println(addresses);
}
}
编写spring配置文件(applicationContext.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="userService" class="com.xr.service.UserService">
<!--二选一即可-->
<!--方式一:通过构造注入list集合-->
<constructor-arg name="addresses">
<list>
<value>南美</value>
<value>非洲</value>
</list>
</constructor-arg>
<!--通过set注入list集合-->
<property name="addresses">
<list>
<value>北京</value>
<value>上海</value>
</list>
</property>
</bean>
</beans>
编写main方法
package com.xr;
import com.xr.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext application = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService bean = application.getBean(UserService.class);
// 调用输出方法
bean.say();
}
}
最后执行结果
4. 注解
上面配置了一大堆的东西是不是非常繁琐,注解就是简化了这些配置来达到快速编写代码,简便了在applicationContext.xml文件配置
首先在applicationContext.xml配置扫描注解的基础配置
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">
<!--1.启用注解处理器,这样才可以使用spring提供的注解来配置-->
<context:annotation-config/>
<!--2.配置扫描,将带有注解的类交给spring管理
当撇脂component-scan时,默认就会启用注解处理器,所以可以不用配置注解处理器-->
<context:component-scan base-package="com.xr.zhujie"/>
</beans>
4.1 @Component注解
@Component
是 Spring 框架中的一个通用注解,用于将类标识为 Spring 管理的组件(即 Bean)。
标注在类上面,表示当前类将纳入容器管理,去掉xml中的<bean/>标签的配置
注解中的value属性表示在容器中的唯一标识,想当于xml中<bean/>标签id属性
简化了在xml配置bean的操作
定义一个UserController类,并在该类中标明@Component注解
/**
* 使用Component标注,表示该类由spring容器管理,想当于xml中<bean/> 标签
* 注解值表示在spring容器的唯一标识,相当于xml中<bean/>标签的id属性
*/
@Component("userController")
public class UserController {
public void say(){
System.out.println("使用了Component注解,将该类交给了spring容器管理");
}
}
4.2 MVC三大注解(@Controller、@Service、@Repository)
Spring 还提供了三个针对不同层次的特定注解,它们都是
@Component
的特殊化形式
@Controller
:用于表示控制层组件,处理用户请求和响应。@Service
:用于表示服务层组件,承载业务逻辑。@Repository
:用于表示持久层组件,负责数据持久化操作。
这三个注解标注在不同层上,和@Component具有相同的效果,额外增加了细化语义效果
创建三个包(controller,service,dao),在这三个包下分别创建3个类(userController,userService,userDao)
userController类(@Controller层)
/**
* 表示这是控制层
*/
@Controller
public class userController {
public void say() {
System.out.println("使用@Controller注解标注类上,可以不使用@Component注解,表示这是控制层,用于接收请求,返回响应");
}
}
userService类(@Service)
/**
* 表示这是服务层
*/
@Service
public class userController {
public void say() {
System.out.println("使用@Service注解标注类上,可以不使用@Component注解,表示这是服务层,用于处理业务逻辑");
}
}
userDao类(@Repository )
/**
* 表示这是持久层
*/
@Repository
public class userController {
public void say() {
System.out.println("使用@Repositroy注解标注类上,可以不使用@Component注解,表示这是数据持久层,用于将数据持久化到数据库");
}
}
4.3 @Scope注解
@Scope
是 Spring 框架中用于指定 Bean 作用域的注解。通过使用@Scope
,开发者可以控制 Spring 容器如何创建和管理 Bean 的实例,从而满足不同的需求
默认为单例,不写注解值为单例,指定值为prototype就是原型(多例)
创建UserService类
@Scope("prototype")
public class UserService{
public void say() {
System.out.println("使用Scope注解,指定注解值为prototype,该类为原型,既多例,不写注解值为单例");
}
}
4.4 生命周期注解(@PostConstruct、@PoreDestory)
@PostConstruct
和@PreDestroy
是 Java 标准中的注解,定义在javax.annotation
包中。这两个注解用于在 Bean 的生命周期中执行特定的方法:
@PostConstruct
:在 Bean 完成依赖注入后、初始化方法执行前调用,用于进行初始化操作。@PreDestroy
:在 Bean 销毁之前调用,用于进行资源释放等清理操作。
因为他是外部依赖,所以需要到pom.xml引用javax的依赖
原型创建的Bean时不会执行销毁方法的,因为创建的对象不受容器管理,Scope指定为prototype,就是临时对象
4.4.1 在pom文件中配置javax依赖
<!--要使用生命周期的注解时需要导入此包-->
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
4.4.2 @PostConstruct注解(bean初始化)
@PostConstruct相当上面生命周期中2.1.1和2.1.2的两个案例
创建一个UserController类
@Controller
public void UserController {
/**
* 等价于xml中init-method属性
*/
@PostConstruct
public void init() {
System.out.println("bean的初始化,当一启动,构造方法先执行,在执行该方法");
}
}
编写Main方法
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
}
执行结果
4.4.3 @PreDestory注解(bean销毁)
@PreDestory相当上面生命周期中2.2.1和2.2.2的两个案例
@PreDestory注解等价xml中destory-method属性
原型创建的Bean时不会执行销毁方法的,因为创建的对象不受容器管理,Scope指定为prototype,就是临时对象(也就是多例)
在UserController类基础上增加destory()方法
@Controller
public void UserController {
/**
* 等价于xml中init-method属性
*/
@PostConstruct
public void init() {
System.out.println("bean的初始化,当一启动,构造方法先执行,在执行该方法");
}
/**
* @PreDestroy等价于destroy-method
*/
@PreDestroy
public void destory() {
System.out.println("bean销毁,当容器销毁之前,执行销毁方法,在销毁容器");
}
}
编写Main方法
public class Main {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
// 销毁容器
((ClassPathXmlApplicationContext)ctx).close();
}
最后执行结果
4.5 依赖注入注解(@Inject、@Named)
@Inject用于依赖注入,相当于上面的3.1.1构造方法注入bean
@Inject 用于通过构造方法和set方法注入bean
@Named 当接口有多个实现类时,通过@Named可以指定注入的Bean(实现类)
创建controller,service包,在controller包下创建UserController类,在service包下创建userService接口,在到service包下创建子包impl,最后在impl包创建UserServiceImpl类并实现userService接口
UserService接口
public interface UserService {
// 添加用户
void add();
}
UserServiceImpl类
@Service
public class UserServiceImpl implments UserService{
public void add() {
System.out.println("添加用户");
}
}
UserController类
该类需要注入UserService的实现类(bean),并调用add方法
@Controller
public class UserController {
// UserService接口
private UserService userService;
/**
* 构造方法注入
* 注意:从spring4.3版本开始,如果构造方法注入时,
* 注入的依赖只有一个实现类时,spring默认就会将这个实现类注入进来
* 但注解需要写在属性上
* @param userService
*/
@Inject
public UserController(UserService userService) {
this.userService = userService;
}
// 添加用户
public void add() {
// 调用注入bean的add方法
userService.add();
}
}
不编写构造方法时,并且只有一个实现类时,@Inject注解应该放在属性上
从spring4.3版本开始,如果构造方法注入时,
只有一个实现类时,spring默认就会将这个实现类注入进来
@Controller
public class UserController {
@Inject
private UserService userService;
// 添加用户
public void add() {
// 调用注入bean的add方法
userService.add();
}
}
编写Main方法
public class Main {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserController controller = (UserController) context.getBean("userController");
controller.add();
}
}
最后执行结果
当UserService接口有多个实现类时,使用@Named注解来指定注入的实现类
在impl包下在添加UserService接口的实现类StudentServiceImpl
/*
* @Service注解值表示在容器中bean标签的id属性,唯一标识
*/
@Service("studentService")
public class StudentServiceImpl implments UserService {
public void add() {
System.out.println("添加学生信息");
}
}
UserController类使用@Named注解来指定注入的实现类
@Controller
public class UserController {
private UserService userService;
/**
* 通过set方法来注入
* 使用@Inject注解进行注入
* 当有多个实现类时,可以结合@Named注解来指定想要注入的Bean的id
* @param userService
*/
@Inject
@Named("studentService")
public void setUserService(UserService userService) {
this.userService = userService;
}
public void add() {
userService.add();
}
}
现在UserService接口有了两个实现类(UserServiceImpl,StudentServiceImpl)了,userController类通过@Named注解指定了注入的实现类为StudentServiceImpl,所以最终执行的结果为添加学生信息
4.6@Resource注解
@Resourcce注解同样是依赖注入,他是使用JSR250(java规提案)
提供的@Resource注解实现依赖注入。
* 它有一个name属性,在注入时指定需要注入的bean的id。这个注解
* 可以标注在类的字段上,也可以标注在set方法上实现注入功能,
* 但不支持标注在构造方法上,这是它的局限性。
UserService接口
public interface UserService {
// 添加用户
void add();
}
UserServiceImpl类
@Service
public class UserServiceImpl implments UserService{
public void add() {
System.out.println("添加用户信息");
}
}
UserController类
将@Resource注解标注在类的字段上
@Controller
public class UserController {
// 标注在类的字段上面
@Resource
private UserService userService;
// 调用userService的add方法
public void add() {
userService.add();
}
}
编写Main方法
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserController controller = context.getBean(UserController.class);
controller.addUser();
}
最后执行结果
将@Ressource注解标注在set方法上
UserController类
@Controller
public class UserController {
// 需要注入的bean,生成对应的set方法
private UserService userService;
/**
* 将Resource注解标注在set方法上,默认会去掉set将set后面第一个字母改小写
* 已userService命名
*/
@Resource
public void setUserService(UserServive usreService) {
this.userService = userService;
}
public void add() {
userService.add();
}
}
执行结果与上面同等
4.7 @Autowired注解、@Qualifier
@Autowired注解于@Resource注解作用一致
@Autowired由spring提供的注入注解
@Autowired注解可以标注在属性、构造方法、set方法上,而@Resource注解不支持标注在构造方法上
@Qualifier注解用于当依赖对象有多个实现类时,指定具体的一个实现类,等价于上面4.5中的@Named注解
如果不想使用@Qualifier注解时可以在实现类上使用@Primary注解来指定注入的优先级
创建UserService接口,并创建UserServiceImpl类,并实现UserService接口,在创建UserController类
UserService接口
public interface UserService {
pubic void add();
}
UserServiceImpl类
@Service
public class UserServiceImpl implments UserService {
@Override
public void add() {
System.out.println("添加用户信息!");
}
}
UserController类
将@Autowired注解标注在构造上
@Controller
public class UserController {
private UserService userService;
/*
* 将@Autorired标注在构造方法上
*/
@Autowired
public UserController(UserService userService){
this.userService = userService;
}
public void add() {
userService.add();
}
}
将@Autowired标注在属性上,无需编写构造方法
@Controller
public Class UserController{
/*
* 将注解标注在属性上,注解自动生成构造方法注入bean
*/
@Autowired
private UserService userService;
public void add() {
userService.add();
}
}
将@Autowired注解标注在set方法上
@Controller
public Class UserController {
private UserService userService;
/**
* 标注在set方法,name为将set去掉后面第一个字母改成小写(userService)
*/
@Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
public void add() {
usereService.add();
}
}
编写Main方法
public Class Main{
public static void main(String[] args) {
ApplicationContext contex = new ClassPathXmlApplicationContext("applicationContext.xml");
UserController userController = (UserController) context.getBean("userController");
userController.add();
}
}
最后执行结果
使用@Qualifier注解,当UserService接口在增加一个实现类时,这个时候就需要指定注入哪个实现类了
创建StudentServiceImpl类,并实现了UserService接口
@Service
public class StudentServiceImpl implments UserService {
@Override
public void add() {
System.out.println("添加学生信息");
}
}
修改UserController类,使用@Qualifier注解指定注入的实现类
在构造方法上使用
@Controller
public class UserController {
private UserService userService;
/**
* 在构造方法中的参数指定注入的实现类为studentService
* @Qualifier注解不能标注在构造方法上,只能标注在参数中
*/
@Autowired
public UserController(@Qualifier("studentService") UserService userService) {
this.userService = userService;
}
}
在set方法中使用
@Controller
public class UserController {
private UserService userService;
/**
* 在set方法的参数指定注入的实现类为studentService
*/
@Autowired
public setUserController(@Qualifier("studentService") UserService userService) {
this.userService = userService;
}
/*@Qualifier可以在set方法上标注,也可以在方法参数标注,二选一*/
/*@Autowired
@Qualifier("studentService")
public setUserController(UserService userService) {
this.userService = userService;
}*/
}
最后执行结果:
如果不想使用@Qualifier注解指定注入的实现类,可以使用@Primary注解设置Bean注入的优先级别
/**
* @Primary注解可以设置Bean注入优先级别
* 你要指定哪个实现类需要注入就在哪加
*/
@Service
@Primary
public class StudentServiceImpl implments UserService {
@Override
public void add() {
System.out.println("添加学生信息");
}
}
执行结果
4.8 @RequiredArgsConstructor 注解
@RequiredArgsConstructor注解也是依赖注入的一种,有lombok提供,使用时需要导入lombok依赖
导入lombox的依赖
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.32</version>
</dependency>
修改UserController
/**
* 使用lombok来生成一个带参的构造方法
* 注意:赋值的字段必须是final
*/
@Controller
@RequiredArgsConstructor
public class userController {
// 注入的对象必须使用final关键字修饰
private final userService userService;
public void add() {
userService.add();
}
}
最后执行结果:
待更新