Spring 注解_IOC容器
- (一)、组件注册
- 1. @Configuration 与 @Bean 容器注册组件
- (1).无注解注入方式
- (2).注解注入方式
- 2. @ComponentScan 自动扫描组件和自动扫描规则
- (1).无注解扫描方式
- (2).注解扫描注入方式
- (3).指定扫描或不扫描的包 (过滤)
- 3. 自定义TypeFilter指定过滤规则 @Filter
- (1).自定义我们的扫描过滤器
- 4.设置组件的作用域 @Scope
- (1).组件默认是单实列
- (2).修改为多实列 (注解)
- (3).使用我们的XML文件进行实现多实列
- 5.@Layz-bean懒加载
- (1).懒加载
- 6.@Conditional 按照条件注册bean
- (1).按照一定的条件进行注册bean
- 7.@Import给容器中快速导入一个组件
- (1).@Import
- (2).ImportSelector ⭐
- (3). ImportBeanDefinitionRegistrar
- (4).FactoryBean
- (二)、组件的生命周期
- 1.@Bean指定初始化和销毁方法
- (1). 使用配置文件进行自定义我们的初始化方法和销毁方法 (==第一种==)
- (2).通过@Bean注解进行初始化和销毁 (==第二种==)
- 2.InitializingBean与 DisposableBean 进行初始化和销毁 (==第三种==)
- (1).通过实现接口进行初始化和销毁的操作
- 3.使用JSR250规范 (==第四种==)
- (1).@PostConstruct 和 @PreDestroy
- 4.BeanPostProcessor后置处理器 (==第五种==)
- (1).BeanPostProcessor 后置处理器
- 5.Spring底层对BeanPostProcessor的使用
- (1). 【案例1】在实体类中获取ioc容器
- (三)、属性赋值相关的注解
- 1.@Value
- (1).普通属性赋值 和 SPEL表达式赋值
- 2. @PropertySource 加载外部配置文件
- (1).使用配置文件的方式加载外部文件
- (2).使用注解的方式 加载外部文件
- (四)、自动装配
- 1.@Autowired 自动装配
- (1). 自动装配(原理是从IOC容器中获得值并赋值)
- (2).@AutoWried(先类型后属性名)
- (3).@Qualifier 配合 @AutoWried
- (4).@Primary 首选装配
- 2.@Resource 和 @Inject [JSR标准]
- (1).@Resource 自动装配
- (2).@Inject 自动装配
- 3.@Autowried自动装配原理
- (1).标注在Set方法位置上
- (2).标注在有参构造方法上
- (3).@Bean + 方法参数
- 4.自定义组件使用Spring容器底层的一些组件
- (1).xxxAware
- 5.@Profile 切换多个应用场景
- (1). 环境搭建
- (2).根据环境注册bean (环境切换)
(一)、组件注册
1. @Configuration 与 @Bean 容器注册组件
(1).无注解注入方式
- 在pom文件中加入spring-context依赖: xml文件和注解的包
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
- 定义一个实体类
package com.jsxs.bean;
/**
* @Author Jsxs
* @Date 2023/8/11 19:57
* @PackageName:com.jsxs.bean
* @ClassName: Person
* @Description: TODO
* @Version 1.0
*/
public class Person {
private String name;
private Integer age;
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
public 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;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
- 在resource目录下的beans.xml配置文件中通过< bean>< /bean>标签注入类实例
<?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="person" class="com.jsxs.bean.Person">
<property name="name" value="李明"></property>
<property name="age" value="19"></property>
</bean>
</beans>
- 获取容器中通过配置文件注入的实例对象
package com.jsxs;
import com.jsxs.bean.Person;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @Author Jsxs
* @Date 2023/8/11 20:14
* @PackageName:com.jsxs
* @ClassName: MainTest
* @Description: TODO
* @Version 1.0
*/
public class MainTest {
public static void main(String[] args) {
// 通过配置文件,创建ioc容器,并向容器中注入实列对象
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
// 根据bean的id获取容器中注入的实列对象
Person person = (Person)applicationContext.getBean("person");
System.out.println(person);
}
}
(2).注解注入方式
1.MyConfig.java
package com.jsxs.config;
import com.jsxs.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Author Jsxs
* @Date 2023/8/12 9:05
* @PackageName:com.jsxs.config
* @ClassName: MyConfig
* @Description: TODO
* @Version 1.0
*/
@Configuration
public class MyConfig {
@Bean
public Person person(){
return new Person("李三",21);
}
}
2.Main.java
package com.jsxs;
import com.jsxs.bean.Person;
import com.jsxs.config.MyConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @Author Jsxs
* @Date 2023/8/12 9:07
* @PackageName:com.jsxs
* @ClassName: Main
* @Description: TODO
* @Version 1.0
*/
public class Main {
public static void main(String[] args) {
// 读取通过配置类,创建ioc容器,并向容器中注入实例对象
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
Person person = (Person)applicationContext.getBean("person");
System.out.println(person);
}
}
2. @ComponentScan 自动扫描组件和自动扫描规则
(1).无注解扫描方式
只要我们加上 @Configuration 这个注解,这个类就会默认加入IOC容器。
- 设置三个组件,并通过包扫描的方式进行注入我们的容器。
package com.jsxs.Mapper;
import org.springframework.stereotype.Repository;
/**
* @Author Jsxs
* @Date 2023/8/12 9:39
* @PackageName:com.jsxs.Mapper
* @ClassName: BookMapper
* @Description: TODO
* @Version 1.0
*/
@Repository
public class BookMapper {
}
package com.jsxs.service;
import org.springframework.stereotype.Service;
/**
* @Author Jsxs
* @Date 2023/8/12 9:33
* @PackageName:com.jsxs.service
* @ClassName: BookService
* @Description: TODO
* @Version 1.0
*/
@Service
public class BookService {
}
package com.jsxs.controller;
import org.springframework.stereotype.Controller;
/**
* @Author Jsxs
* @Date 2023/8/12 9:33
* @PackageName:com.jsxs.controller
* @ClassName: BookController
* @Description: TODO
* @Version 1.0
*/
@Controller
public class BookController {
}
1. beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
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.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!-- 包自动扫描: 凡是带有 @Controller @Service @Repository @Component -->
<context:component-scan base-package="com.jsxs"/>
<!-- 通过Bean的方式进行我们的组件注入的操作 -->
<bean id="person" class="com.jsxs.bean.Person">
<property name="name" value="李明"/>
<property name="age" value="19"/>
</bean>
</beans>
2.IOCTest.java
package com.jsxs.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @Author Jsxs
* @Date 2023/8/12 9:39
* @PackageName:com.jsxs.Test
* @ClassName: IOCTest
* @Description: TODO
* @Version 1.0
*/
public class IOCTest {
public static void main(String[] args) {
// 读取通过配置文件注入容器中实列
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
// 进行遍历的操作
for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
}
}
}
(2).注解扫描注入方式
MyConfig.java
带有@Configuration的注解一开始就会被默认加入我们的组件中去。
package com.jsxs.config;
import com.jsxs.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* @Author Jsxs
* @Date 2023/8/12 9:05
* @PackageName:com.jsxs.config
* @ClassName: MyConfig
* @Description: TODO
* @Version 1.0
*/
@ComponentScan(value = "com.jsxs")
@Configuration
public class MyConfig {
@Bean
public Person person(){
return new Person("李三",21);
}
}
(3).指定扫描或不扫描的包 (过滤)
- 使用
@ComponentScan
进行操作扫描包 - (排除xxx)
package com.jsxs.config;
import com.jsxs.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;
/**
* @Author Jsxs
* @Date 2023/8/12 9:05
* @PackageName:com.jsxs.config
* @ClassName: MyConfig
* @Description: TODO
* @Version 1.0
*/
// 指定扫描com.jsxs这个包下面的全部文件,但是排除掉注解为 Controller 和 Service 的组件
@ComponentScan(value = "com.jsxs",
excludeFilters = { // 这里是排除掉xxx
@ComponentScan.Filter(
type = FilterType.ANNOTATION,
classes = {
Controller.class,
Service.class
}
)
})
@Configuration
public class MyConfig {
@Bean
public Person person() {
return new Person("李三", 21);
}
}
结果我们发现: 我们IOC容器中的组件中少我们指定的Controller 和 Service 这两个组件标注的组件
- 使用
@ComponentScans
进行扫描多个 @ComponentScan (不排除xxx)
package com.jsxs.config;
import com.jsxs.bean.Person;
import org.springframework.context.annotation.*;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;
/**
* @Author Jsxs
* @Date 2023/8/12 9:05
* @PackageName:com.jsxs.config
* @ClassName: MyConfig
* @Description: TODO
* @Version 1.0
*/
// 这里可以通过 @ComponentScans 配置多个 @@ComponentScan
@ComponentScans(value = {
// 指定扫描com.jsxs这个包下面的全部文件,但是排除掉注解为 Controller 和 Service 的组件
@ComponentScan(value = "com.jsxs",
includeFilters = { // 这里是只有包含这些组件的才被打印出来
@ComponentScan.Filter(
type = FilterType.ANNOTATION, classes = {Controller.class, Service.class}
)}, useDefaultFilters = false) // 这里就相当于把所有的非includeFilters全部过滤掉,不显示(默认为true)
})
@Configuration
public class MyConfig {
@Bean
public Person person() {
return new Person("李三", 21);
}
}
我们发现我们的结果 只有我们通过配置
3. 自定义TypeFilter指定过滤规则 @Filter
(1).自定义我们的扫描过滤器
1. 过滤的文件是这样写的
package com.jsxs.config;
import org.springframework.core.io.Resource;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;
import java.io.IOException;
/**
* @Author Jsxs
* @Date 2023/8/12 19:57
* @PackageName:com.jsxs.config
* @ClassName: MyTypeFilter
* @Description: TODO 自定义过滤的话,我们需要实现这个 TypeFilter 接口
* @Version 1.0
*/
public class MyTypeFilter implements TypeFilter { //⭐
/**
*
* @param metadataReader : 读取当前正在扫描的类
* @param metadataReaderFactory : 可以获取到其他任何类的信息
* @return
* @throws IOException
*/
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
// 1.获取当前类注解的信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
// 2.获取当前正在扫描的类的类信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();
// 3.获取当前类资源(类路径)
Resource resource = metadataReader.getResource();
// 4.获取当前类的类名
String className = classMetadata.getClassName();
System.out.println("---> "+className);
// 5.假如 类名中存在 er 的话,我们就将这个容器注入到组件中去
if (className.contains("er")){
return true;
}
return false;
}
}
2. 配置文件是这样写的
package com.jsxs.config;
import com.jsxs.Mapper.BookMapper;
import com.jsxs.bean.Person;
import com.jsxs.service.BookService;
import org.springframework.context.annotation.*;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;
/**
* @Author Jsxs
* @Date 2023/8/12 9:05
* @PackageName:com.jsxs.config
* @ClassName: MyConfig
* @Description: TODO
* @Version 1.0
*/
/**
* TODO: 1. ANNOTATION 按照注解 ; 2. ASSIGNABLE_TYPE 按照给定的类型 3.CUSTOM 自定义规则
*/
// 1. 这里是一个数组,可以包含多个@ComponentScan
@ComponentScans(value = {
// 2. 指定扫描com.jsxs这个包下面的全部文件,但是排除掉注解为 Controller 和 Service 的组件
@ComponentScan(value = "com.jsxs",
// 3. 这里是一个数组,可以包含多个 Filter
includeFilters = { // 4. 这里是只有包含这些组件的才被打印出来
// 4.1 第一个Filter ⭐
@ComponentScan.Filter( // 5. 类型是注解 ; 要过滤的类文件
type = FilterType.ANNOTATION, classes = {Controller.class, Service.class}
),
// 4.2 第二个Filter ⭐
@ComponentScan.Filter(
type = FilterType.ASSIGNABLE_TYPE,classes = {BookMapper.class}
),
// 4.3 第三个Filter ⭐
@ComponentScan.Filter( // 5.指向我们自定义的过滤类信息
type = FilterType.CUSTOM,classes = {MyTypeFilter.class}
)
}, useDefaultFilters = false) // 这里就相当于把所有的非includeFilters全部过滤掉,不显示
})
@Configuration
public class MyConfig {
@Bean
public Person person() {
return new Person("李三", 21);
}
}
4.设置组件的作用域 @Scope
(1).组件默认是单实列
组件默认在IOC容器中是单实列的,也就是说我们在IOC容器中使用的组件都是同一个组件。
1. 进行编写我们的配置文件
package com.jsxs.config;
import com.jsxs.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Author Jsxs
* @Date 2023/8/12 20:20
* @PackageName:com.jsxs.config
* @ClassName: MyConfig2
* @Description: TODO
* @Version 1.0
*/
@Configuration
public class MyConfig2 {
@Bean("person2")
public Person person(){
return new Person("张三2",22);
}
}
2.测试类
package com.jsxs.Test;
import com.jsxs.bean.Person;
import com.jsxs.config.MyConfig2;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @Author Jsxs
* @Date 2023/8/12 20:22
* @PackageName:com.jsxs.Test
* @ClassName: Main_Ann2
* @Description: TODO
* @Version 1.0
*/
public class Main_Ann2 {
public static void main(String[] args) {
// 1.将这个配置文件中的组件放入我们的IOC容器中
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig2.class);
// 2.通过我们的组件名获取我们指定的组件信息
Person person = (Person)applicationContext.getBean("person2");
Person person2 = (Person)applicationContext.getBean("person2");
// 3.打印出我们的组件信息
System.out.println(person);
// 4.遍历我们所有的组件
for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
}
// 5.组件默认是单实列的 即 在IOC容器中,我们一直使用的都是同一个组件
System.out.println("判断是否是一个单实列的,结果是:"+(person2==person));
}
}
(2).修改为多实列 (注解)
package com.jsxs.config;
import com.jsxs.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
/**
* @Author Jsxs
* @Date 2023/8/12 20:20
* @PackageName:com.jsxs.config
* @ClassName: MyConfig2
* @Description: TODO
* @Version 1.0
*/
@Configuration
public class MyConfig2 {
/** 1. singleton 但是列的
* 2.prototype 多实列 (默认值)
* 3. 同一次请求创建一个实列
* 4. 同一个session创建一个实列
*/
@Scope(value = "prototype") // ⭐ 我们这在里修改为多实列的
@Bean("person2")
public Person person(){
return new Person("张三2",22);
}
}
package com.jsxs.Test;
import com.jsxs.bean.Person;
import com.jsxs.config.MyConfig2;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @Author Jsxs
* @Date 2023/8/12 20:22
* @PackageName:com.jsxs.Test
* @ClassName: Main_Ann2
* @Description: TODO
* @Version 1.0
*/
public class Main_Ann2 {
public static void main(String[] args) {
// 1.将这个配置文件中的组件放入我们的IOC容器中
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig2.class);
// 2.通过我们的组件名获取我们指定的组件信息
Person person = (Person)applicationContext.getBean("person2");
Person person2 = (Person)applicationContext.getBean("person2");
// 3.打印出我们的组件信息
System.out.println(person);
// 4.遍历我们所有的组件
for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
}
// 5.组件默认是单实列的 即 在IOC容器中,我们一直使用的都是同一个组件 ⭐
System.out.println("判断是否是一个单实列的,结果是:"+(person2==person));
}
}
(3).使用我们的XML文件进行实现多实列
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
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.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!-- 包自动扫描: 凡是带有 @Controller @Service @Repository @Component -->
<context:component-scan base-package="com.jsxs"/>
<!-- 通过Bean的方式进行我们的组件注入的操作 -->
<bean id="person" class="com.jsxs.bean.Person" scope="prototype">
<property name="name" value="李明"/>
<property name="age" value="19"/>
</bean>
</beans>
小结: 我们使用多实列的情况下,我们的组件并不会在IOC创建完成的时候进创建我们的实列,而是当我们使用到组件的时候,才会帮助我们创建我们的实列。 (懒汉式)
单实列: 我们的组件会在我们的容器创建完成之后就会帮助我们创建我们的实列。 (饿汉式)
5.@Layz-bean懒加载
(1).懒加载
单实例bean,默认在容器创建启动的时候就会创建对象。但是在懒加载模式下,容器启动的时候不会创建对象,而是在第一次使用(获取)Bean的时候才会创建并初始化。
单实列 + 懒加载 ≠ 多实例
1. 设置配置类的组件为 单实列+懒加载
package com.jsxs.config;
import com.jsxs.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope;
/**
* @Author Jsxs
* @Date 2023/8/12 20:20
* @PackageName:com.jsxs.config
* @ClassName: MyConfig2
* @Description: TODO
* @Version 1.0
*/
@Configuration
public class MyConfig2 {
/** 1. singleton 但是列的
* 2.prototype 多实列 (默认值)
* 3. 同一次请求创建一个实列
* 4. 同一个session创建一个实列
*/
@Scope(value = "prototype") //⭐
@Bean("person2")
@Lazy //⭐
public Person person(){
return new Person("张三2",22);
}
}
2.进行测试
package com.jsxs.Test;
import com.jsxs.bean.Person;
import com.jsxs.config.MyConfig2;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @Author Jsxs
* @Date 2023/8/12 20:22
* @PackageName:com.jsxs.Test
* @ClassName: Main_Ann2
* @Description: TODO
* @Version 1.0
*/
public class Main_Ann2 {
public static void main(String[] args) {
// 1.将这个配置文件中的组件放入我们的IOC容器中
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig2.class);
// 2.通过我们的组件名获取我们指定的组件信息
Person person = (Person)applicationContext.getBean("person2");
Person person2 = (Person)applicationContext.getBean("person2");
// 3.打印出我们的组件信息
System.out.println(person);
// 4.遍历我们所有的组件
for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
}
// 5.组件默认是单实列的 即 在IOC容器中,我们一直使用的都是同一个组件
System.out.println("判断是否是一个单实列的,结果是:"+(person2==person));
}
}
因为懒加载的意思就是当我们使用的时候才回去创建实列,又因为是单实列的所以我们只会创建一次
6.@Conditional 按照条件注册bean
(1).按照一定的条件进行注册bean
按照一定的条件进行判断,满足条件时才给容器中注册bean。
这里我们要实现 condition 的接口,因为我们的@Conditional({参数}),这里的参数就是我们需要继承 condition 的接口。
WindowConditional.java
package com.jsxs.conditional;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;
/**
* @Author Jsxs
* @Date 2023/8/13 19:18
* @PackageName:com.jsxs.conditional
* @ClassName: WindowConditional
* @Description: TODO
* @Version 1.0
*/
public class WindowConditional implements Condition { //⭐
/**
*
* @param context : 可以获取到上下文
* @param metadata : 注解
* @return
*/
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment environment = context.getEnvironment();
if (environment.getProperty("os.name").contains("Windows")){
return true;
}
return false;
}
}
LinuxConditional.java
package com.jsxs.conditional;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;
/**
* @Author Jsxs
* @Date 2023/8/13 19:18
* @PackageName:com.jsxs.conditional
* @ClassName: LinuxConditional
* @Description: TODO 我们需要继承Condition这个接口
* @Version 1.0
*/
public class LinuxConditional implements Condition { //⭐
/**
*
* @param context : 判断条件能使用的上下文(环境)
* @param metadata : 注释信息
* @return
*/
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// 1. 能获取到IOC使用的beanFactory
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
// 2. 能获取到类加载器
ClassLoader classLoader = context.getClassLoader();
// 3. 获取我们的开发环境
Environment environment = context.getEnvironment();
// 4.获取到bean定义的注册类
BeanDefinitionRegistry registry = context.getRegistry();
if (environment.getProperty("os.name").contains("Linux")){
return true;
}
return false;
}
}
MyConfig2.java
package com.jsxs.config;
import com.jsxs.bean.Person;
import com.jsxs.conditional.LinuxConditional;
import com.jsxs.conditional.WindowConditional;
import org.springframework.context.annotation.*;
/**
* @Author Jsxs
* @Date 2023/8/12 20:20
* @PackageName:com.jsxs.config
* @ClassName: MyConfig2
* @Description: TODO
* @Version 1.0
*/
@Configuration
public class MyConfig2 {
/*
@ conditional({condition列表}) 按照条件进行注入我们的组件
提出需求: 假如我们的系统是window系统的话,那么我们就注册 person01 这个组件,如果是linux系统的话 我们就注册 person02 这个组件。
*/
@Conditional({WindowConditional.class}) //⭐
@Bean("person01")
public Person person01(){
return new Person("张三01",33);
}
@Conditional(LinuxConditional.class) // ⭐
@Bean("person02")
public Person person02(){
return new Person("张三02",33);
}
}
7.@Import给容器中快速导入一个组件
这个注解需要放在我们的配置类上,因为配置类项目刚启动的时候就会加载进组件,我们IOC需要识别到这个 @Import
才能继续工作。
/**
* 给容器中注册组件
* 1. 包扫描 + 组件标注注解 (repository,service controller component)
* 2. @Configuration + @Bean
* 3. @Import[快速给容器导入一个组件]
* (1).@Import(要导入的容器),容器中会自动注册这个组件,id默认是全限定名。
* (2).@ImportSelector: 返回需要导入的组件的全限定名数组。
* 4.FactoryBean: 使用Spring提供的FactoryBean (工厂Bean)
*/
(1).@Import
1.要注册的组件
package com.jsxs.bean;
/**
* @Author Jsxs
* @Date 2023/8/13 20:54
* @PackageName:com.jsxs.bean
* @ClassName: Color
* @Description: TODO
* @Version 1.0
*/
public class Color {
}
2.@Import注解放在类上
package com.jsxs.config;
import com.jsxs.bean.Color;
import com.jsxs.bean.Person;
import com.jsxs.conditional.LinuxConditional;
import com.jsxs.conditional.WindowConditional;
import org.springframework.context.annotation.*;
/**
* @Author Jsxs
* @Date 2023/8/12 20:20
* @PackageName:com.jsxs.config
* @ClassName: MyConfig2
* @Description: TODO
* @Version 1.0
*/
@Configuration
// 快速的导入组件,id默认的是全限定名 ⭐
@Import(Color.class)
public class MyConfig2 {
/**
* 1. singleton 但是列的
* 2.prototype 多实列 (默认值)
* 3. 同一次请求创建一个实列
* 4. 同一个session创建一个实列
*/
@Scope(value = "singleton")
@Bean("person2")
@Lazy
public Person person() {
return new Person("张三2", 22);
}
/*
@ conditional({condition列表}) 按照条件进行注入我们的组件
提出需求: 假如我们的系统是window系统的话,那么我们就注册 person01 这个组件,如果是linux系统的话 我们就注册 person02 这个组件。
*/
@Conditional({WindowConditional.class})
@Bean("person01")
public Person person01() {
return new Person("张三01", 33);
}
@Conditional(LinuxConditional.class)
@Bean("person02")
public Person person02() {
return new Person("张三02", 33);
}
}
3.测试
package com.jsxs.Test;
import com.jsxs.bean.Person;
import com.jsxs.config.MyConfig2;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
/**
* @Author Jsxs
* @Date 2023/8/12 20:22
* @PackageName:com.jsxs.Test
* @ClassName: Main_Ann2
* @Description: TODO
* @Version 1.0
*/
public class Main_Ann2 {
public static void main(String[] args) {
// 1.将这个配置文件中的组件放入我们的IOC容器中
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig2.class);
// 2.我们可以通过IOC容器获取我们的运行环境,然后获取我们的系统环境
ConfigurableEnvironment environment = applicationContext.getEnvironment();
System.out.println(environment.getSystemEnvironment());
// 3.获取我们具体的属性名
System.out.println(environment.getProperty("os.name"));
// 2.遍历我们所有的组件
for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
}
}
}
(2).ImportSelector ⭐
假如我们的类实现了 ImportSelector
的接口,那么我们这个类的返回值就是我们需要注入IOC容器中组件的全限定名。.
1.MyImportSelector.java
package com.jsxs.conditional;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
/**
* @Author Jsxs
* @Date 2023/8/13 21:07
* @PackageName:com.jsxs.conditional
* @ClassName: MyImportSelector
* @Description: TODO 自定义逻辑返回需要导入的组件
* @Version 1.0
*/
public class MyImportSelector implements ImportSelector {
/**
*
* @param importingClassMetadata : 当前标注@Import注解的类的所有注解信息
* @return : 返回值就是导入容器中的组件全类名
*/
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"com.jsxs.bean.Yellow","com.jsxs.bean.Red"}; // ⭐
}
}
package com.jsxs.config;
import com.jsxs.bean.Color;
import com.jsxs.bean.Person;
import com.jsxs.conditional.LinuxConditional;
import com.jsxs.conditional.MyImportSelector;
import com.jsxs.conditional.WindowConditional;
import org.springframework.context.annotation.*;
/**
* @Author Jsxs
* @Date 2023/8/12 20:20
* @PackageName:com.jsxs.config
* @ClassName: MyConfig2
* @Description: TODO
* @Version 1.0
*/
@Configuration
// 快速的导入组件,id默认的是全限定名 ⭐⭐
@Import({Color.class, MyImportSelector.class})
public class MyConfig2 {
/**
* 1. singleton 但是列的
* 2.prototype 多实列 (默认值)
* 3. 同一次请求创建一个实列
* 4. 同一个session创建一个实列
*/
@Scope(value = "singleton")
@Bean("person2")
@Lazy
public Person person() {
return new Person("张三2", 22);
}
/*
@ conditional({condition列表}) 按照条件进行注入我们的组件
提出需求: 假如我们的系统是window系统的话,那么我们就注册 person01 这个组件,如果是linux系统的话 我们就注册 person02 这个组件。
*/
@Conditional({WindowConditional.class})
@Bean("person01")
public Person person01() {
return new Person("张三01", 33);
}
@Conditional(LinuxConditional.class)
@Bean("person02")
public Person person02() {
return new Person("张三02", 33);
}
/**
* 给容器中注册组件
* 1. 包扫描 + 组件标注注解 (repository,service controller component)
* 2. @Configuration + @Bean
* 3. @Import
*/
}
(3). ImportBeanDefinitionRegistrar
1.我们需要实现一个接口 ImportBeanDefinitionRegistrar
package com.jsxs.conditional;
import com.jsxs.bean.RainBow;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
/**
* @Author Jsxs
* @Date 2023/8/14 8:44
* @PackageName:com.jsxs.conditional
* @ClassName: MyImportBeanDefinitionRegistrar
* @Description: TODO
* @Version 1.0
*/
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
/**
*
* @param importingClassMetadata : 当前类的注解信息
* @param registry : BeanDefinition注册类
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// 1.先判断我们的容器中是否有有我们将要注入IOC容器的组件
if (registry.containsBeanDefinition("com.jsxs.bean.Color")) {
// 第一个参数是我们注册后的组件名叫什么,第二个参数是我们需要使用类的全限定名 ⭐
registry.registerBeanDefinition("RainBow",new RootBeanDefinition(RainBow.class));
}
}
}
2. 配置类编写
package com.jsxs.config;
import com.jsxs.bean.Color;
import com.jsxs.bean.Person;
import com.jsxs.conditional.LinuxConditional;
import com.jsxs.conditional.MyImportBeanDefinitionRegistrar;
import com.jsxs.conditional.MyImportSelector;
import com.jsxs.conditional.WindowConditional;
import org.springframework.context.annotation.*;
/**
* @Author Jsxs
* @Date 2023/8/12 20:20
* @PackageName:com.jsxs.config
* @ClassName: MyConfig2
* @Description: TODO
* @Version 1.0
*/
@Configuration
// 快速的导入组件,id默认的是全限定名 ⭐⭐
@Import({Color.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
public class MyConfig2 {
/**
* 1. singleton 但是列的
* 2.prototype 多实列 (默认值)
* 3. 同一次请求创建一个实列
* 4. 同一个session创建一个实列
*/
@Scope(value = "singleton")
@Bean("person2")
@Lazy
public Person person() {
return new Person("张三2", 22);
}
/*
@ conditional({condition列表}) 按照条件进行注入我们的组件
提出需求: 假如我们的系统是window系统的话,那么我们就注册 person01 这个组件,如果是linux系统的话 我们就注册 person02 这个组件。
*/
@Conditional({WindowConditional.class})
@Bean("person01")
public Person person01() {
return new Person("张三01", 33);
}
@Conditional(LinuxConditional.class)
@Bean("person02")
public Person person02() {
return new Person("张三02", 33);
}
}
3.进行测试的操作
package com.jsxs.Test;
import com.jsxs.bean.Person;
import com.jsxs.config.MyConfig2;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
/**
* @Author Jsxs
* @Date 2023/8/12 20:22
* @PackageName:com.jsxs.Test
* @ClassName: Main_Ann2
* @Description: TODO
* @Version 1.0
*/
public class Main_Ann2 {
public static void main(String[] args) {
// 1.将这个配置文件中的组件放入我们的IOC容器中
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig2.class);
// 2.我们可以通过IOC容器获取我们的运行环境,然后获取我们的系统环境
ConfigurableEnvironment environment = applicationContext.getEnvironment();
System.out.println(environment.getSystemEnvironment());
// 3.获取我们具体的属性名
System.out.println(environment.getProperty("os.name"));
// 2.遍历我们所有的组件
for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
}
}
}
(4).FactoryBean
第四种在IOC容器中注入我们的组件的方法就是 我们Spring提供的 FactoryBean 工厂。我们只需要实现接口 FactoryBean< T> 这里的 T 就是我们需要的被注入IOC容器的组件类名称。
1. 实际要被注入IOC容器的类
package com.jsxs.bean;
/**
* @Author Jsxs
* @Date 2023/8/14 9:53
* @PackageName:com.jsxs.bean
* @ClassName: Color_factory
* @Description: TODO
* @Version 1.0
*/
public class Color_factory {
}
2.实现我们的接口
package com.jsxs.bean;
import org.springframework.beans.factory.FactoryBean;
/**
* @Author Jsxs
* @Date 2023/8/14 9:15
* @PackageName:com.jsxs.bean
* @ClassName: ColorFactoryBean
* @Description: TODO
* @Version 1.0
*/
// 创建一个Spring定义的FactoryBean ⭐
public class ColorFactoryBean implements FactoryBean<Color_factory> { // 这里我们指定我们的类型T为 我们想要注册的组件
// 1.返回一个 ColorFactoryBean 对象,这个对象会添加到容器中去 ⭐
@Override
public Color_factory getObject() throws Exception {
return new Color_factory();
}
// 2.返回类的类型 ⭐
@Override
public Class<?> getObjectType() {
return Color_factory.class;
}
// 3. 是否是单列? ⭐
/**
*
* @return : 假如说为true,那么我们就是单实列的,假如说为false,那么我们就不是单实列的。
*/
@Override
public boolean isSingleton() {
return false;
}
}
3.配置类中注册我们的ColorFactoryBean
@Bean
public ColorFactoryBean colorFactoryBean(){
return new ColorFactoryBean();
}
4.测试输出
package com.jsxs.Test;
import com.jsxs.bean.Person;
import com.jsxs.config.MyConfig2;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
/**
* @Author Jsxs
* @Date 2023/8/12 20:22
* @PackageName:com.jsxs.Test
* @ClassName: Main_Ann2
* @Description: TODO
* @Version 1.0
*/
public class Main_Ann2 {
public static void main(String[] args) {
// 1.将这个配置文件中的组件放入我们的IOC容器中
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig2.class);
// 2.我们可以通过IOC容器获取我们的运行环境,然后获取我们的系统环境
ConfigurableEnvironment environment = applicationContext.getEnvironment();
System.out.println(environment.getSystemEnvironment());
// 3.获取我们具体的属性名
System.out.println(environment.getProperty("os.name"));
// 2.遍历我们所有的组件
for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
}
System.out.println(applicationContext.getBean("colorFactoryBean")+"-----");
}
}
遍历所有组件,我们只会得到表象为 colorFactory 这个组件。实际上我们通过组件的名字获取这个colorFactory便会得到我们实际上注入组件的类型和名字。
com.jsxs.bean.Color_factory@276438c9 这个是实际上注入的组件
(二)、组件的生命周期
1.@Bean指定初始化和销毁方法
(1). 使用配置文件进行自定义我们的初始化方法和销毁方法 (第一种)
(2).通过@Bean注解进行初始化和销毁 (第二种)
- 当对象创建完成后,并赋值好之后,调用初始化方法。
- 容器关闭之后,调用销毁的方法
* Bean的生命周期
* bean 创建 -> 初始化 -> 销毁的过程
* 容器管理bean的生命周期; 我们可以自定义生命周期中的 初始化环节和销毁的环节。容器在bean运行到当前生命周期的时候来调用我们自定义的初始化和销毁方法。
* 1. init-method="" destroy-method=""
* 2. 构造(对象创建)
* 单实列: 在容器启动的时候创建对象
* 多实列: 在调用到组件的时候创建对象
1.Car.java
package com.jsxs.bean;
/**
* @Author Jsxs
* @Date 2023/8/14 17:12
* @PackageName:com.jsxs.bean
* @ClassName: Car
* @Description: TODO
* @Version 1.0
*/
public class Car {
public Car(){
System.out.println("Car Constructor ....");
}
public void init(){
System.out.println("Car Init...");
}
public void destroy(){
System.out.println("Car Destroy...");
}
}
2.配置类
package com.jsxs.config;
import com.jsxs.bean.Car;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Author Jsxs
* @Date 2023/8/14 17:04
* @PackageName:com.jsxs.config
* @ClassName: MainConfigOfLifeCycle
* @Description: TODO Bean的生命周期
* bean 创建 -> 初始化 -> 销毁的过程
* 容器管理bean的生命周期; 我们可以自定义生命周期中的 初始化环节和销毁的环节。容器在bean运行到当前生命周期的时候来调用我们自定义的初始化和销毁方法。
* 1. init-method="" destroy-method=""
* 2. 构造(对象创建)
* 单实列: 在容器启动的时候创建对象
* 多实列: 在调用到组件的时候创建对象
* @Version 1.0
*/
@Configuration
public class MainConfigOfLifeCycle {
// 第一个参数是指定组件的别名,第二参数是指定组件的销毁方法,第三个参数是指定组件的初始方法。 ⭐
@Bean(value = "car",destroyMethod = "destroy",initMethod = "init")
public Car car(){
return new Car();
}
}
3.测试
package com.jsxs.Test;
import com.jsxs.config.MainConfigOfLifeCycle;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @Author Jsxs
* @Date 2023/8/14 17:16
* @PackageName:com.jsxs.Test
* @ClassName: IOC_LifeStyle
* @Description: TODO
* @Version 1.0
*/
public class IOC_LifeStyle {
public static void main(String[] args) {
// 1.创建IOC容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
// 2.关闭容器,当容器关闭的时候我们所有的组件也就会销毁
applicationContext.close();
// 1.遍历所有IOC容器中的组件
for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
}
}
}
2.InitializingBean与 DisposableBean 进行初始化和销毁 (第三种)
(1).通过实现接口进行初始化和销毁的操作
1.我们需要自定义的bean只需要实现两个接口InitializingBean, DisposableBean即可
package com.jsxs.bean;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
/**
* @Author Jsxs
* @Date 2023/8/14 19:57
* @PackageName:com.jsxs.bean
* @ClassName: Car01
* @Description: TODO
* @Version 1.0
*/
public class Car01 implements InitializingBean, DisposableBean {
public Car01() {
}
// 1.初始化的操作
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("Car01进行初始化...");
}
// 2.销毁的操作
@Override
public void destroy() throws Exception {
System.out.println("Car01进行销毁...");
}
}
package com.jsxs.config;
import com.jsxs.bean.Car;
import com.jsxs.bean.Car01;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Author Jsxs
* @Date 2023/8/14 17:04
* @PackageName:com.jsxs.config
* @ClassName: MainConfigOfLifeCycle
* @Description: TODO Bean的生命周期
* bean 创建 -> 初始化 -> 销毁的过程
* 容器管理bean的生命周期; 我们可以自定义生命周期中的 初始化环节和销毁的环节。容器在bean运行到当前生命周期的时候来调用我们自定义的初始化和销毁方法。
* 1. init-method="" destroy-method=""
* 2. 构造(对象创建)
* 单实列: 在容器启动的时候创建对象
* 多实列: 在调用到组件的时候创建对象
* @Version 1.0
*/
@Configuration
public class MainConfigOfLifeCycle {
@Bean
public Car01 car01() {
return new Car01();
}
}
3.使用JSR250规范 (第四种)
(1).@PostConstruct 和 @PreDestroy
@PostConstruct
:在bean创建完成并且属性值赋值完成后执行初始化;
@PreDestroy
:在容器销毁bean之前,通知容器进行清理工作;
1.需要被注册的组件
package com.jsxs.bean;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
/**
* @Author Jsxs
* @Date 2023/8/16 15:37
* @PackageName:com.jsxs.bean
* @ClassName: Dog
* @Description: TODO
* @Version 1.0
*/
public class Dog {
public Dog() {
System.out.println("dog constructor...");
}
@PostConstruct ⭐
public void init() {
System.out.println("dog 初始化中...");
}
@PreDestroy() ⭐
public void destroy() {
System.out.println("dog 销毁中...");
}
}
2.配置类: 注册需要的组件
package com.jsxs.config;
import com.jsxs.bean.Car;
import com.jsxs.bean.Car01;
import com.jsxs.bean.Dog;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Author Jsxs
* @Date 2023/8/14 17:04
* @PackageName:com.jsxs.config
* @ClassName: MainConfigOfLifeCycle
* @Description: TODO Bean的生命周期
* bean 创建 -> 初始化 -> 销毁的过程
* 容器管理bean的生命周期; 我们可以自定义生命周期中的 初始化环节和销毁的环节。容器在bean运行到当前生命周期的时候来调用我们自定义的初始化和销毁方法。
* 1. init-method="" destroy-method=""
* 2. 构造(对象创建)
* 单实列: 在容器启动的时候创建对象
* 多实列: 在调用到组件的时候创建对象
* @Version 1.0
*/
@Configuration
public class MainConfigOfLifeCycle {
// 第一个参数是指定组件的别名,第二参数是指定组件的销毁方法,第三个参数是指定组件的初始方法。
@Bean(value = "car", destroyMethod = "destroy", initMethod = "init")
public Car car() {
return new Car();
}
@Bean
public Car01 car01() {
return new Car01();
}
@Bean ⭐
public Dog dog(){
return new Dog();
}
}
3.测试
package com.jsxs.Test;
import com.jsxs.config.MainConfigOfLifeCycle;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @Author Jsxs
* @Date 2023/8/14 17:16
* @PackageName:com.jsxs.Test
* @ClassName: IOC_LifeStyle
* @Description: TODO
* @Version 1.0
*/
public class IOC_LifeStyle {
public static void main(String[] args) {
// 1.创建IOC容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
// 2.关闭容器,当容器关闭的时候我们所有的组件也就会销毁
applicationContext.close();
// 1.遍历所有IOC容器中的组件
for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
}
}
}
4.BeanPostProcessor后置处理器 (第五种)
(1).BeanPostProcessor 后置处理器
后置处理器相当于在组件初始化之前做什么,初始化之后我们还做什么?
我们的Bean需要继承一个接口 BeanPostProcessor
并且完成两个方法。
在bean的初始化方法之前和初始化方法之后进行一些处理工作。注意是初始化方法,和销毁方法没有一毛钱的关系。
初始化方法之前: 调用:postProcessBeforeInitialization()
初始化方法之后:调用:postProcessAfterInitialization()
即使没有自定义初始化方法,在组件创建前后,后置处理器方法也会执行。
1.注册我们的后置处理器
package com.jsxs.bean;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
/**
* @Author Jsxs
* @Date 2023/8/16 15:51
* @PackageName:com.jsxs.bean
* @ClassName: MyBeanPostProcessor
* @Description: TODO 我们需要实现一个 BeanPostProcessor 接口,并且完成两个方法
* @Version 1.0
*/
@Component ⭐
public class MyBeanPostProcessor implements BeanPostProcessor { ⭐⭐
/**
* @param bean 新建组件的实列
* @param beanName 新建组件实列的名字
* @return 返回的是组件的信息
* @throws BeansException
*/
@Override ⭐⭐⭐
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println(beanName + "----->" + bean);
return bean;
}
/**
* @param bean 新建组件的实列
* @param beanName 新建组件实列的名字
* @return 返回的是组件的信息
* @throws BeansException
*/
@Override ⭐⭐⭐⭐
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println(beanName + "----->" + bean);
return bean;
}
}
2.配置类扫描我们的后置处理器
package com.jsxs.config;
import com.jsxs.bean.Car;
import com.jsxs.bean.Car01;
import com.jsxs.bean.Dog;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* @Author Jsxs
* @Date 2023/8/14 17:04
* @PackageName:com.jsxs.config
* @ClassName: MainConfigOfLifeCycle
* @Description: TODO Bean的生命周期
* bean 创建 -> 初始化 -> 销毁的过程
* 容器管理bean的生命周期; 我们可以自定义生命周期中的 初始化环节和销毁的环节。容器在bean运行到当前生命周期的时候来调用我们自定义的初始化和销毁方法。
* 1. init-method="" destroy-method=""
* 2. 构造(对象创建)
* 单实列: 在容器启动的时候创建对象
* 多实列: 在调用到组件的时候创建对象
* @Version 1.0
*/
@Configuration
@ComponentScan(value = "com.jsxs") ⭐
public class MainConfigOfLifeCycle {
// 第一个参数是指定组件的别名,第二参数是指定组件的销毁方法,第三个参数是指定组件的初始方法。
@Bean(value = "car", destroyMethod = "destroy", initMethod = "init")
public Car car() {
return new Car();
}
@Bean
public Car01 car01() {
return new Car01();
}
@Bean
public Dog dog(){
return new Dog();
}
}
3.测试类
package com.jsxs.Test;
import com.jsxs.config.MainConfigOfLifeCycle;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @Author Jsxs
* @Date 2023/8/14 17:16
* @PackageName:com.jsxs.Test
* @ClassName: IOC_LifeStyle
* @Description: TODO
* @Version 1.0
*/
public class IOC_LifeStyle {
public static void main(String[] args) {
// 1.创建IOC容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
// 2.关闭容器,当容器关闭的时候我们所有的组件也就会销毁
applicationContext.close();
// 1.遍历所有IOC容器中的组件
for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
}
}
}
5.Spring底层对BeanPostProcessor的使用
(1). 【案例1】在实体类中获取ioc容器
1.实体类
package com.jsxs.bean;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
/**
* @Author Jsxs
* @Date 2023/8/16 15:37
* @PackageName:com.jsxs.bean
* @ClassName: Dog
* @Description: TODO
* @Version 1.0
*/
public class Dog implements ApplicationContextAware { // ⭐继承这个IOC接口
private ApplicationContext applicationContext; // ⭐⭐
public Dog() {
System.out.println("dog constructor...");
}
@PostConstruct
public void init() {
System.out.println("dog 初始化中...");
}
@PreDestroy()
public void destroy() {
System.out.println("dog 销毁中...");
}
@Override // ⭐⭐⭐
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext=applicationContext;
}
// ⭐⭐⭐⭐ 自己写一个获取IOC容器的方法 (便于调用)
public ApplicationContext getApplicationContext(){
return applicationContext;
}
}
2.测试
package com.jsxs.Test;
import com.jsxs.bean.Dog;
import com.jsxs.config.MainConfigOfLifeCycle;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
/**
* @Author Jsxs
* @Date 2023/8/14 17:16
* @PackageName:com.jsxs.Test
* @ClassName: IOC_LifeStyle
* @Description: TODO
* @Version 1.0
*/
public class IOC_LifeStyle {
public static void main(String[] args) {
// 1.创建IOC容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
// 2.关闭容器,当容器关闭的时候我们所有的组件也就会销毁
applicationContext.close();
// 1.遍历所有IOC容器中的组件
for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
}
ConfigurableEnvironment environment1 = applicationContext.getEnvironment();
System.out.println(environment1.getProperty("os.name"));
// ⭐我们创建实列,并且
Dog dog = new Dog();
ApplicationContext applicationContext1 = dog.getApplicationContext();
for (String beanDefinitionName : applicationContext1.getBeanDefinitionNames()) {
System.out.println("--->"+beanDefinitionName);
}
}
}
(三)、属性赋值相关的注解
/**
* 使用@Value赋值
* 1、基本数值
* 2、可以些SpEL,#{}
* 3、可以写${},取出配置文件中的值(即在运行环境变量中的值).
* 通过@PropertySource注解将properties配置文件中的值存储到Spring的 Environment中,
* Environment接口提供方法去读取配置文件中的值,参数是properties文件中定义的key值。
*/
1.@Value
(1).普通属性赋值 和 SPEL表达式赋值
1.需要注册的组件
package com.jsxs.bean;
import org.springframework.beans.factory.annotation.Value;
/**
* @Author Jsxs
* @Date 2023/8/11 19:57
* @PackageName:com.jsxs.bean
* @ClassName: Person
* @Description: TODO
* @Version 1.0
*/
public class Person {
// ⭐
@Value("李明")
private String name;
// ⭐⭐ spel表达式
@Value("#{20-2}")
private Integer age;
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
public 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;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
2.配置类
package com.jsxs.config;
import com.jsxs.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Author Jsxs
* @Date 2023/8/17 9:05
* @PackageName:com.jsxs.config
* @ClassName: MainConfigOfPropertyValues
* @Description: TODO
* @Version 1.0
*/
@Configuration
public class MainConfigOfPropertyValues {
@Bean
public Person person() {
return new Person();
}
}
3.测试
package com.jsxs.Test;
import com.jsxs.bean.Person;
import com.jsxs.config.MainConfigOfPropertyValues;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @Author Jsxs
* @Date 2023/8/17 9:07
* @PackageName:com.jsxs.Test
* @ClassName: IOCTest_PropertyValue
* @Description: TODO
* @Version 1.0
*/
public class IOCTest_PropertyValue {
public static void main(String[] args) {
// 1.创建IOC容器
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(MainConfigOfPropertyValues.class);
for (String beanDefinitionName : annotationConfigApplicationContext.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
}
// 2.通过组件名获取具体的组件信息
Person person = (Person)annotationConfigApplicationContext.getBean("person");
System.out.println(person);
}
}
2. @PropertySource 加载外部配置文件
(1).使用配置文件的方式加载外部文件
1.beans.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
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.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!-- 1.包自动扫描: 凡是带有 @Controller @Service @Repository @Component -->
<context:component-scan base-package="com.jsxs"/>
<!-- 2.从外部环境中获取值 ⭐-->
<context:property-placeholder location="classpath:person.properties"/>
<!-- 3. 通过Bean的方式进行我们的组件注入的操作 并设置作用域为多实例 -->
<bean id="person" class="com.jsxs.bean.Person" scope="prototype">
<!-- 4.从外部环境中获取值使用EL表达式 ⭐⭐-->
<property name="name" value="${person.name}"/>
<property name="age" value="19"/>
</bean>
</beans>
2.resource/beans.xml
person.name=李明
3.Person.java 实体类
package com.jsxs.bean;
import org.springframework.beans.factory.annotation.Value;
/**
* @Author Jsxs
* @Date 2023/8/11 19:57
* @PackageName:com.jsxs.bean
* @ClassName: Person
* @Description: TODO
* @Version 1.0
*/
public class Person {
/**
* 1.基本数值
* 2. 可以写Spel表达式,#{}
* 3.可以写${},取出配置文件中的值(即在运行环境中的值)
* 通过@PropertySource注解将properties配置文件中的值存储到Spring的 Environment中,
* Environment接口提供方法去读取配置文件中的值,参数是properties文件中定义的key值。
*/
// ⭐⭐ 假如说这里加了@Value("${})注解也不会生效
private String name;
@Value("#{20-2}")
private Integer age;
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
public 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;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
4.测试的操作
package com.jsxs.Test;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @Author Jsxs
* @Date 2023/8/17 10:15
* @PackageName:com.jsxs.Test
* @ClassName: IOCTest_PropertyValue_anno
* @Description: TODO
* @Version 1.0
*/
public class IOCTest_PropertyValue_XML {
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
}
System.out.println(applicationContext.getBean("person"));
}
}
结果:我们取到了我们外部的文件,但是因为是中文,所以出现中文乱码的操作
(2).使用注解的方式 加载外部文件
1.Person.java
package com.jsxs.bean;
import org.springframework.beans.factory.annotation.Value;
/**
* @Author Jsxs
* @Date 2023/8/11 19:57
* @PackageName:com.jsxs.bean
* @ClassName: Person
* @Description: TODO
* @Version 1.0
*/
public class Person {
/**
* 1.基本数值
* 2. 可以写Spel表达式,#{}
* 3.可以写${},取出配置文件中的值(即在运行环境中的值)
* 通过@PropertySource注解将properties配置文件中的值存储到Spring的 Environment中,
* Environment接口提供方法去读取配置文件中的值,参数是properties文件中定义的key值。
*/
// ⭐⭐
@Value("${person.name}")
private String name;
@Value("#{20-2}")
private Integer age;
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
public 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;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
2.配置文件 person.properties
person.name=asd
3.配置类
package com.jsxs.config;
import com.jsxs.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
/**
* @Author Jsxs
* @Date 2023/8/17 9:05
* @PackageName:com.jsxs.config
* @ClassName: MainConfigOfPropertyValues
* @Description: TODO
* @Version 1.0
*/
// ⭐⭐ 配置文件不写了,但是我们需要在配置类上添加这个注解用来指定我们去哪个配置文件中进行获取数据
@PropertySource(value = {"classpath:person.properties"})
@Configuration
public class MainConfigOfPropertyValues {
@Bean
public Person person() {
return new Person();
}
}
4.测试类
package com.jsxs.Test;
import com.jsxs.bean.Person;
import com.jsxs.config.MainConfigOfPropertyValues;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @Author Jsxs
* @Date 2023/8/17 9:07
* @PackageName:com.jsxs.Test
* @ClassName: IOCTest_PropertyValue
* @Description: TODO
* @Version 1.0
*/
public class IOCTest_PropertyValue {
public static void main(String[] args) {
// 1.创建IOC容器
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(MainConfigOfPropertyValues.class);
for (String beanDefinitionName : annotationConfigApplicationContext.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
}
// 2.通过组件名获取具体的组件信息
Person person = (Person)annotationConfigApplicationContext.getBean("person");
System.out.println(person);
}
}
(四)、自动装配
什么是自动装配?
Spring利用依赖注入(DI),完成对IOC容器中各个组件的依赖关系赋值
1.@Autowired 自动装配
/**
* @Author Jsxs
* @Date 2023/8/17 11:14
* @PackageName:com.jsxs.config
* @ClassName: MainConfigOfAutowried
* @Description: TODO
* 自动装配:
* Spring利用依赖注入(DI),完成对IOC容器中各个组件的依赖关系赋值
* 1. @Autowired:自动注入
* 原理:假如我们service类需要用到dao类那么我们在service中声明 dao类为私有变量并加上@Autowired注解
* (1).那么默认按照类型去容器中找对应的组件: 好比如: applicationContext.getBean(BookMapper.class); 假如找到一个的话,那么就从IOC容器中取值并赋值
* (2).如果找到多个相同类型的组件,再将属性的名称作为的id去容器中查找。 比如: applicationContext.getBean("bookMapper") 通过具体组件名获取
* (3).如果想指定使用某一个同类型不同命的组件,那么需要使用 @Qualifier("book2") 进行指定需要的组件
* @Version 1.0
*/
(1). 自动装配(原理是从IOC容器中获得值并赋值)
1.BookMapper.java
package com.jsxs.mapper;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
/**
* @Author Jsxs
* @Date 2023/8/12 9:39
* @PackageName:com.jsxs.Mapper
* @ClassName: BookMapper
* @Description: TODO
* @Version 1.0
*/
@Repository
public class BookMapper {
private String label="1";
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
@Override
public String toString() {
return "BookMapper{" +
"label='" + label + '\'' +
'}';
}
}
2.BookService.java
package com.jsxs.service;
import com.jsxs.mapper.BookMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @Author Jsxs
* @Date 2023/8/12 9:33
* @PackageName:com.jsxs.service
* @ClassName: BookService
* @Description: TODO
* @Version 1.0
*/
@Service
public class BookService {
// ⭐⭐
@Autowired
private BookMapper bookMapper;
public void print(){
System.out.println("1111111111111111111"+bookMapper);
}
@Override
public String toString() {
return "BookService{" +
"bookMapper=" + bookMapper +
'}';
}
}
3.配置类的书写
package com.jsxs.config;
import com.jsxs.mapper.BookMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* @Author Jsxs
* @Date 2023/8/17 11:14
* @PackageName:com.jsxs.config
* @ClassName: MainConfigOfAutowried
* @Description: TODO
* 自动装配:
* Spring利用依赖注入(DI),完成对IOC容器中各个组件的依赖关系赋值
* 1. @Autowired:自动注入
* 原理:假如我们service类需要用到dao类那么我们在service中声明 dao类为私有变量并加上@Autowired注解
* (1).那么默认按照类型去容器中找对应的组件: 好比如: applicationContext.getBean(BookMapper.class); 假如找到一个的话,那么就从IOC容器中取值并赋值
* (2).如果找到多个相同类型的组件,再将属性的名称作为的id去容器中查找。 applicationContext.getBean("bookMapper")
* @Version 1.0
*/
@Configuration
@ComponentScan(value = "com.jsxs") // ⭐⭐
public class MainConfigOfAutowried {
}
4.测试
package com.jsxs.Test;
import com.jsxs.mapper.BookMapper;
import com.jsxs.config.MainConfigOfAutowried;
import com.jsxs.service.BookService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @Author Jsxs
* @Date 2023/8/17 11:23
* @PackageName:com.jsxs.Test
* @ClassName: IOCTest_Autowried
* @Description: TODO
* @Version 1.0
*/
public class IOCTest_Autowried {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAutowried.class);
for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
}
// 判断我们是否是从IOC容器中获得值并赋值?
BookMapper bean = applicationContext.getBean(BookMapper.class);
BookService bean1 = applicationContext.getBean(BookService.class);
System.out.println(bean1);
System.out.println(bean);
}
}
(2).@AutoWried(先类型后属性名)
这里我们第一个组件通过 @Reposity 注解扫描注入IOC容器,然后第二个组件通过 @Bean 的方式注入IOC容器。所以在这里我们就会发现在同一个IOC容器中有两个相同类型但不同名
的组件。
1.BookMapper.java
package com.jsxs.mapper;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
/**
* @Author Jsxs
* @Date 2023/8/12 9:39
* @PackageName:com.jsxs.Mapper
* @ClassName: BookMapper
* @Description: TODO
* @Version 1.0
*/
// 组件1
@Repository
public class BookMapper {
private String label="1";
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
@Override
public String toString() {
return "BookMapper{" +
"label='" + label + '\'' +
'}';
}
}
2.BookService.java
package com.jsxs.service;
import com.jsxs.mapper.BookMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @Author Jsxs
* @Date 2023/8/12 9:33
* @PackageName:com.jsxs.service
* @ClassName: BookService
* @Description: TODO
* @Version 1.0
*/
@Service
public class BookService {
@Autowired
private BookMapper bookMapper;
public void print(){
System.out.println(bookMapper);
}
@Override
public String toString() {
return "BookService{" +
"bookMapper=" + bookMapper +
'}';
}
}
3.配置类
package com.jsxs.config;
import com.jsxs.mapper.BookMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* @Author Jsxs
* @Date 2023/8/17 11:14
* @PackageName:com.jsxs.config
* @ClassName: MainConfigOfAutowried
* @Description: TODO
* 自动装配:
* Spring利用依赖注入(DI),完成对IOC容器中各个组件的依赖关系赋值
* 1. @Autowired:自动注入
* 原理:假如我们service类需要用到dao类那么我们在service中声明 dao类为私有变量并加上@Autowired注解
* (1).那么默认按照类型去容器中找对应的组件: 好比如: applicationContext.getBean(BookMapper.class); 假如找到一个的话,那么就从IOC容器中取值并赋值
* (2).如果找到多个相同类型的组件,再将属性的名称作为的id去容器中查找。 applicationContext.getBean("bookMapper")
* @Version 1.0
*/
@Configuration
@ComponentScan(value = "com.jsxs")
public class MainConfigOfAutowried {
// ⭐ 通过@Bena注入的同类型不同命组件
@Bean("book2")
public BookMapper bookMapper() {
BookMapper bookMapper = new BookMapper();
bookMapper.setLabel("2");
return bookMapper;
}
}
4.测试类
package com.jsxs.Test;
import com.jsxs.mapper.BookMapper;
import com.jsxs.config.MainConfigOfAutowried;
import com.jsxs.service.BookService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @Author Jsxs
* @Date 2023/8/17 11:23
* @PackageName:com.jsxs.Test
* @ClassName: IOCTest_Autowried
* @Description: TODO
* @Version 1.0
*/
public class IOCTest_Autowried {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAutowried.class);
for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
}
BookService bean1 = applicationContext.getBean(BookService.class);
System.out.println(bean1);
}
}
证明在同一个IOC容器中有两个相同类型但不同名的组件。
(3).@Qualifier 配合 @AutoWried
假如我们注入一个组件并未指定他的组件名,那么组件名就会默认是 首字母小写的驼峰命名。所以使用这个组件的目的主要是为了解决 相同类型但不同组件名 的需求。
1.BookMapper.java
package com.jsxs.mapper;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
/**
* @Author Jsxs
* @Date 2023/8/12 9:39
* @PackageName:com.jsxs.Mapper
* @ClassName: BookMapper
* @Description: TODO
* @Version 1.0
*/
@Repository // ⭐组件一
public class BookMapper {
private String label="1";
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
@Override
public String toString() {
return "BookMapper{" +
"label='" + label + '\'' +
'}';
}
}
2.BookService.java
package com.jsxs.service;
import com.jsxs.mapper.BookMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
/**
* @Author Jsxs
* @Date 2023/8/12 9:33
* @PackageName:com.jsxs.service
* @ClassName: BookService
* @Description: TODO
* @Version 1.0
*/
@Service
public class BookService {
@Autowired // ⭐ 自动装配
@Qualifier("book2") // 指定名字
private BookMapper bookMapper;
public void print(){
System.out.println(bookMapper);
}
@Override
public String toString() {
return "BookService{" +
"bookMapper=" + bookMapper +
'}';
}
}
3.配置类
package com.jsxs.config;
import com.jsxs.mapper.BookMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* @Author Jsxs
* @Date 2023/8/17 11:14
* @PackageName:com.jsxs.config
* @ClassName: MainConfigOfAutowried
* @Description: TODO
* 自动装配:
* Spring利用依赖注入(DI),完成对IOC容器中各个组件的依赖关系赋值
* 1. @Autowired:自动注入
* 原理:假如我们service类需要用到dao类那么我们在service中声明 dao类为私有变量并加上@Autowired注解
* (1).那么默认按照类型去容器中找对应的组件: 好比如: applicationContext.getBean(BookMapper.class); 假如找到一个的话,那么就从IOC容器中取值并赋值
* (2).如果找到多个相同类型的组件,再将属性的名称作为的id去容器中查找。 比如: applicationContext.getBean("bookMapper") 通过具体组件名获取
* (3).如果想指定使用某一个同类型不同命的组件,那么需要使用 @Qualifier("book2") 进行指定需要的组件
* @Version 1.0
*/
@Configuration
@ComponentScan(value = "com.jsxs") // ⭐扫描
public class MainConfigOfAutowried {
@Bean("book2") // ⭐⭐ 组件二
public BookMapper bookMapper() {
BookMapper bookMapper = new BookMapper();
bookMapper.setLabel("2");
return bookMapper;
}
}
4.测试
package com.jsxs.Test;
import com.jsxs.mapper.BookMapper;
import com.jsxs.config.MainConfigOfAutowried;
import com.jsxs.service.BookService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @Author Jsxs
* @Date 2023/8/17 11:23
* @PackageName:com.jsxs.Test
* @ClassName: IOCTest_Autowried
* @Description: TODO
* @Version 1.0
*/
public class IOCTest_Autowried {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAutowried.class);
for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
}
BookService bean1 = applicationContext.getBean(BookService.class);
System.out.println(bean1);
}
}
(4).@Primary 首选装配
常用于: 相同类型不同名的组件,然后相比于 @Quailfier() 的使用是 在使用组件的时候添加,@Primary是在组件创建的时候,就默认未首选装配。
1.BookMapper.java
package com.jsxs.mapper;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
/**
* @Author Jsxs
* @Date 2023/8/12 9:39
* @PackageName:com.jsxs.Mapper
* @ClassName: BookMapper
* @Description: TODO
* @Version 1.0
*/
@Repository
public class BookMapper {
private String label="1";
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
@Override
public String toString() {
return "BookMapper{" +
"label='" + label + '\'' +
'}';
}
}
2.BookService
package com.jsxs.service;
import com.jsxs.mapper.BookMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
/**
* @Author Jsxs
* @Date 2023/8/12 9:33
* @PackageName:com.jsxs.service
* @ClassName: BookService
* @Description: TODO
* @Version 1.0
*/
@Service
public class BookService {
@Autowired
// @Qualifier("book2") ⭐⭐ 这里我们不指定使用哪个具体名字的组件进行装配
private BookMapper bookMapper;
public void print(){
System.out.println("1111111111111111111"+bookMapper);
}
@Override
public String toString() {
return "BookService{" +
"bookMapper=" + bookMapper +
'}';
}
}
3.配置类
package com.jsxs.config;
import com.jsxs.mapper.BookMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
/**
* @Author Jsxs
* @Date 2023/8/17 11:14
* @PackageName:com.jsxs.config
* @ClassName: MainConfigOfAutowried
* @Description: TODO
* 自动装配:
* Spring利用依赖注入(DI),完成对IOC容器中各个组件的依赖关系赋值
* 1. @Autowired:自动注入
* 原理:假如我们service类需要用到dao类那么我们在service中声明 dao类为私有变量并加上@Autowired注解
* (1).那么默认按照类型去容器中找对应的组件: 好比如: applicationContext.getBean(BookMapper.class); 假如找到一个的话,那么就从IOC容器中取值并赋值
* (2).如果找到多个相同类型的组件,再将属性的名称作为的id去容器中查找。 比如: applicationContext.getBean("bookMapper") 通过具体组件名获取
* (3).如果想指定使用某一个同类型不同命的组件,那么需要使用 @Qualifier("book2") 进行指定需要的组件
* (4).@Qualifier("book2")需要在使用的时候加入注解,比较繁琐,我们希望在注册组件的时候就作为首选组件 @Primary
* @Version 1.0
*/
@Configuration
@ComponentScan(value = "com.jsxs")
public class MainConfigOfAutowried {
@Primary // ⭐⭐⭐ 组件在注册的时候,我们就指定使用这个组件进行装配 同类型不同组件命的组件
@Bean("book2")
public BookMapper bookMapper() {
BookMapper bookMapper = new BookMapper();
bookMapper.setLabel("2");
return bookMapper;
}
}
4.测试
package com.jsxs.Test;
import com.jsxs.mapper.BookMapper;
import com.jsxs.config.MainConfigOfAutowried;
import com.jsxs.service.BookService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @Author Jsxs
* @Date 2023/8/17 11:23
* @PackageName:com.jsxs.Test
* @ClassName: IOCTest_Autowried
* @Description: TODO
* @Version 1.0
*/
public class IOCTest_Autowried {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAutowried.class);
for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
}
BookService bean1 = applicationContext.getBean(BookService.class);
System.out.println(bean1);
}
}
2.@Resource 和 @Inject [JSR标准]
Spring 还支持@Resource(JSR250) 和 @Inject(JSR330) [Java 规范]
(1).@Resource 自动装配
1.BookMapper.java
package com.jsxs.mapper;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
/**
* @Author Jsxs
* @Date 2023/8/12 9:39
* @PackageName:com.jsxs.Mapper
* @ClassName: BookMapper
* @Description: TODO
* @Version 1.0
*/
@Repository
public class BookMapper {
private String label="1";
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
@Override
public String toString() {
return "BookMapper{" +
"label='" + label + '\'' +
'}';
}
}
2.BookServer.java
package com.jsxs.service;
import com.jsxs.mapper.BookMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* @Author Jsxs
* @Date 2023/8/12 9:33
* @PackageName:com.jsxs.service
* @ClassName: BookService
* @Description: TODO
* @Version 1.0
*/
@Service
public class BookService {
// ⭐⭐假如需要指定具体的组件的话,我们需要添加name属性,如果不添加name属性的话,就默认按照变量名查找 applicationContext.getBean("bookMapper")
@Resource(name = "book2")
private BookMapper bookMapper;
public void print(){
System.out.println("1111111111111111111"+bookMapper);
}
@Override
public String toString() {
return "BookService{" +
"bookMapper=" + bookMapper +
'}';
}
}
3.配置类
package com.jsxs.config;
import com.jsxs.mapper.BookMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
/**
* @Author Jsxs
* @Date 2023/8/17 11:14
* @PackageName:com.jsxs.config
* @ClassName: MainConfigOfAutowried
* @Description: TODO
* 自动装配:
* Spring利用依赖注入(DI),完成对IOC容器中各个组件的依赖关系赋值
* 1. @Autowired:自动注入
* 原理:假如我们service类需要用到dao类那么我们在service中声明 dao类为私有变量并加上@Autowired注解
* (1).那么默认按照类型去容器中找对应的组件: 好比如: applicationContext.getBean(BookMapper.class); 假如找到一个的话,那么就从IOC容器中取值并赋值
* (2).如果找到多个相同类型的组件,再将属性的名称作为的id去容器中查找。 比如: applicationContext.getBean("bookMapper") 通过具体组件名获取
* (3).如果想指定使用某一个同类型不同命的组件,那么需要使用 @Qualifier("book2") 进行指定需要的组件
* (4).@Qualifier("book2")需要在使用的时候加入注解,比较繁琐,我们希望在注册组件的时候就作为首选组件 @Primary
*
* 2. @Resource: 自动注入 ⭐⭐
* (1).@Resource和@Autowried都可以对IOC容器的组件进行自动装配,但是@Autowried是按照组件的类型和名称进行自动装配的
* (2).@Resource不能支持@Primary和@Quailifer这两个注解
* 3. @Inject: 自动注入
* (1).能够支持@Primary和@Quailifer , 和 @Autowired一样
* (2).但是需要导入一个包
* @Version 1.0
*/
@Configuration
@ComponentScan(value = "com.jsxs")
public class MainConfigOfAutowried {
@Primary // ⭐⭐ 这个添加是没有用的,因为@Resource不支持
@Bean("book2")
public BookMapper bookMapper() {
BookMapper bookMapper = new BookMapper();
bookMapper.setLabel("2");
return bookMapper;
}
}
4.测试类
package com.jsxs.Test;
import com.jsxs.mapper.BookMapper;
import com.jsxs.config.MainConfigOfAutowried;
import com.jsxs.service.BookService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @Author Jsxs
* @Date 2023/8/17 11:23
* @PackageName:com.jsxs.Test
* @ClassName: IOCTest_Autowried
* @Description: TODO
* @Version 1.0
*/
public class IOCTest_Autowried {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAutowried.class);
for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
}
BookService bean1 = applicationContext.getBean(BookService.class);
System.out.println(bean1);
}
}
(2).@Inject 自动装配
1.导入对应的 inject依赖
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
2.BookMapper.java
package com.jsxs.mapper;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
/**
* @Author Jsxs
* @Date 2023/8/12 9:39
* @PackageName:com.jsxs.Mapper
* @ClassName: BookMapper
* @Description: TODO
* @Version 1.0
*/
@Repository
public class BookMapper {
private String label="1";
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
@Override
public String toString() {
return "BookMapper{" +
"label='" + label + '\'' +
'}';
}
}
3.BookService.java
package com.jsxs.service;
import com.jsxs.mapper.BookMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.inject.Inject;
/**
* @Author Jsxs
* @Date 2023/8/12 9:33
* @PackageName:com.jsxs.service
* @ClassName: BookService
* @Description: TODO
* @Version 1.0
*/
@Service
public class BookService {
// @Inject 和 @Autowried 一模一样。 可以使用@Quailifer 和 @Primary ⭐⭐
@Inject
private BookMapper bookMapper;
public void print(){
System.out.println("1111111111111111111"+bookMapper);
}
@Override
public String toString() {
return "BookService{" +
"bookMapper=" + bookMapper +
'}';
}
}
4.配置类
package com.jsxs.config;
import com.jsxs.mapper.BookMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
/**
* @Author Jsxs
* @Date 2023/8/17 11:14
* @PackageName:com.jsxs.config
* @ClassName: MainConfigOfAutowried
* @Description: TODO
* 自动装配:
* Spring利用依赖注入(DI),完成对IOC容器中各个组件的依赖关系赋值
* 1. @Autowired:自动注入
* 原理:假如我们service类需要用到dao类那么我们在service中声明 dao类为私有变量并加上@Autowired注解
* (1).那么默认按照类型去容器中找对应的组件: 好比如: applicationContext.getBean(BookMapper.class); 假如找到一个的话,那么就从IOC容器中取值并赋值
* (2).如果找到多个相同类型的组件,再将属性的名称作为的id去容器中查找。 比如: applicationContext.getBean("bookMapper") 通过具体组件名获取
* (3).如果想指定使用某一个同类型不同命的组件,那么需要使用 @Qualifier("book2") 进行指定需要的组件
* (4).@Qualifier("book2")需要在使用的时候加入注解,比较繁琐,我们希望在注册组件的时候就作为首选组件 @Primary
*
* 2. @Resource: 自动注入
* (1).@Resource和@Autowried都可以对IOC容器的组件进行自动装配,但是@Autowried是按照组件的类型和名称进行自动装配的
* (2).@Resource不能支持@Primary和@Quailifer这两个注解
* 3. @Inject: 自动注入 ⭐⭐
* (1).能够支持@Primary和@Quailifer , 和 @Autowired一样
* (2).但是需要导入一个包
* @Version 1.0
*/
@Configuration
@ComponentScan(value = "com.jsxs")
public class MainConfigOfAutowried {
@Primary // ⭐⭐⭐ 可以使用
@Bean("book2")
public BookMapper bookMapper() {
BookMapper bookMapper = new BookMapper();
bookMapper.setLabel("2");
return bookMapper;
}
}
5.测试
package com.jsxs.Test;
import com.jsxs.mapper.BookMapper;
import com.jsxs.config.MainConfigOfAutowried;
import com.jsxs.service.BookService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @Author Jsxs
* @Date 2023/8/17 11:23
* @PackageName:com.jsxs.Test
* @ClassName: IOCTest_Autowried
* @Description: TODO
* @Version 1.0
*/
public class IOCTest_Autowried {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAutowried.class);
for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
}
BookService bean1 = applicationContext.getBean(BookService.class);
System.out.println(bean1);
}
}
3.@Autowried自动装配原理
通过点击 @Autowried的源码,我们发现这个注解可以标注在构造器上
、方法上
等。
(1).标注在Set方法位置上
// 标注在方法上,Spring容器创建当前对象,就会调用方法,完成赋值的操作。
// 方法使用的参数,自定义类型的参数的值是从IOC容器中获取, 比如说 我们启动IOC容器后,就会在IOC容器中找类型未 Car.class 类型的组件
如果需要自动装配的话,项目要求非要方法上的话,那么一定要优先选择 set 方法。
1. Car.java
package com.jsxs.bean;
import org.springframework.stereotype.Repository;
/**
* @Author Jsxs
* @Date 2023/8/14 17:12
* @PackageName:com.jsxs.bean
* @ClassName: Car
* @Description: TODO
* @Version 1.0
*/
@Repository ⭐
public class Car {
public Car(){
System.out.println("Car Constructor ....");
}
public void init(){
System.out.println("Car Init...");
}
public void destroy(){
System.out.println("Car Destroy...");
}
}
2.Boss.java
package com.jsxs.bean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
/**
* @Author Jsxs
* @Date 2023/8/17 17:34
* @PackageName:com.jsxs.bean
* @ClassName: Boss
* @Description: TODO
* @Version 1.0
*/
@Repository ⭐⭐
public class Boss {
private Car car;
public Boss(Car car) {
this.car = car;
}
public Boss() {
}
public Car getCar() {
return car;
}
@Autowired ⭐⭐⭐
// 标注在方法上,Spring容器创建当前对象,就会调用方法,完成赋值的操作。
// 方法使用的参数,自定义类型的参数的值是从IOC容器中获取, 比如说 我们启动IOC容器后,就会在IOC容器中找类型未 Car.class 类型的组件
public void setCar(Car car) {
this.car = car;
}
@Override
public String toString() {
return "Boss{" +
"car=" + car +
'}';
}
}
3.配置类
package com.jsxs.config;
import com.jsxs.mapper.BookMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
/**
* @Author Jsxs
* @Date 2023/8/17 11:14
* @PackageName:com.jsxs.config
* @ClassName: MainConfigOfAutowried
* @Description: TODO
**/
@Configuration
@ComponentScan(value = "com.jsxs") //⭐⭐⭐ 扫描
public class MainConfigOfAutowried {
@Primary
@Bean("book2")
public BookMapper bookMapper() {
BookMapper bookMapper = new BookMapper();
bookMapper.setLabel("2");
return bookMapper;
}
}
4.测试
package com.jsxs.Test;
import com.jsxs.bean.Boss;
import com.jsxs.bean.Car;
import com.jsxs.mapper.BookMapper;
import com.jsxs.config.MainConfigOfAutowried;
import com.jsxs.service.BookService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @Author Jsxs
* @Date 2023/8/17 11:23
* @PackageName:com.jsxs.Test
* @ClassName: IOCTest_Autowried
* @Description: TODO
* @Version 1.0
*/
public class IOCTest_Autowried {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAutowried.class);
for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
}
// 判断是否是是在IOC容器中获取的
Boss bean = applicationContext.getBean(Boss.class);
Car bean1 = applicationContext.getBean(Car.class);
System.out.println(bean);
System.out.println(bean1);
}
}
(2).标注在有参构造方法上
创建对象默认是调用无参构造方法的,但是因为我们在有参构造方法上添加了@Autowried,那么我们就会在IOC创建后,创建对象的话就会使用有参构造函数进行创建了。
1.Car.java
package com.jsxs.bean;
import org.springframework.stereotype.Repository;
/**
* @Author Jsxs
* @Date 2023/8/14 17:12
* @PackageName:com.jsxs.bean
* @ClassName: Car
* @Description: TODO
* @Version 1.0
*/
@Repository
public class Car {
public Car(){
System.out.println("Car Constructor ....");
}
public void init(){
System.out.println("Car Init...");
}
public void destroy(){
System.out.println("Car Destroy...");
}
}
2.Boss.java
package com.jsxs.bean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
/**
* @Author Jsxs
* @Date 2023/8/17 17:34
* @PackageName:com.jsxs.bean
* @ClassName: Boss
* @Description: TODO
* @Version 1.0
*/
@Repository //⭐扫描后默认加载IOC容器中的组件,容器启动就会(单实列饿汉)调用无参构造器创建对象,再进行初始化赋值等操作。⭐
public class Boss {
private Car car;
@Autowired ⭐⭐
// 标注在方法上,Spring容器创建当前对象,就会调用方法,完成赋值的操作。
// 方法使用的参数,自定义类型的参数的值是从IOC容器中获取, 比如说 我们启动IOC容器后,就会在IOC容器中找类型未 Car.class 类型的组件
public Boss(Car car) {
this.car = car;
}
public Boss() {
}
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
@Override
public String toString() {
return "Boss{" +
"car=" + car +
'}';
}
}
3.配置类
package com.jsxs.config;
import com.jsxs.mapper.BookMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
/**
* @Author Jsxs
* @Date 2023/8/17 11:14
* @PackageName:com.jsxs.config
* @ClassName: MainConfigOfAutowried
* @Description: TODO
**/
@Configuration
@ComponentScan(value = "com.jsxs") //⭐⭐扫描
public class MainConfigOfAutowried {
@Primary
@Bean("book2")
public BookMapper bookMapper() {
BookMapper bookMapper = new BookMapper();
bookMapper.setLabel("2");
return bookMapper;
}
}
4.测试
package com.jsxs.Test;
import com.jsxs.bean.Boss;
import com.jsxs.bean.Car;
import com.jsxs.mapper.BookMapper;
import com.jsxs.config.MainConfigOfAutowried;
import com.jsxs.service.BookService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @Author Jsxs
* @Date 2023/8/17 11:23
* @PackageName:com.jsxs.Test
* @ClassName: IOCTest_Autowried
* @Description: TODO
* @Version 1.0
*/
public class IOCTest_Autowried {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfAutowried.class);
for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
}
Boss bean = applicationContext.getBean(Boss.class);
Car bean1 = applicationContext.getBean(Car.class);
System.out.println(bean);
System.out.println(bean1);
}
}
(3).@Bean + 方法参数
@Bean+方法参数 ,这里的参数默认是从IOC容器中获取的。默认不写@Autowried 也会自动装配
@Primary
@Bean("book2")
public BookMapper bookMapper(Car car) { //⭐ 这个Car 也是从IOC容器中获取的
BookMapper bookMapper = new BookMapper();
bookMapper.setLabel("2");
return bookMapper;
}
4.自定义组件使用Spring容器底层的一些组件
(1).xxxAware
自定义组件实现xxxAware: 在创建对象的时候,会调用接口规定的方法注入相关组件。Aware
5.@Profile 切换多个应用场景
(1). 环境搭建
1.依赖
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
2.配置类
package com.jsxs.config;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.util.StringValueResolver;
import javax.sql.DataSource;
import java.beans.PropertyVetoException;
/**
* @Author Jsxs
* @Date 2023/8/17 20:59
* @PackageName:com.jsxs.config
* @ClassName: MainConfigOfProfile
* @Description: TODO Profile:
* Spring为我们提供的可以根据当前环境,动态的激活和切换一系列bean的功能
* (1).开发环境、测试环境、生产环境
*
* @Version 1.0
*/
@PropertySource("classpath:/db.properties") // 1. 因为要读取外部的文件,所以我们需要指定外部的文件的位置
@Configuration
public class MainConfigOfProfile implements EmbeddedValueResolverAware { // 2.实现EmbeddedValueResolverAware解析器接口,这个接口主要是能够解析 ${} 和 #{}
@Value("${db.user}") // 3. 获取外部的文件,并赋值
private String user;
@Value("${db.password}")
private String password;
@Value("${db.driverClass}")
private String Driver;
// 4. 进行依赖注入的操作
private StringValueResolver stringValueResolver;
@Bean("DataSourceTest")
public DataSource dataSourceTest() throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser(user);
dataSource.setPassword(password);
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/demo1");
dataSource.setDriverClass(Driver);
return dataSource;
}
@Bean("DataSourceDev")
public DataSource dataSourceDev() throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser(user);
dataSource.setPassword(password);
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/library");
dataSource.setDriverClass(Driver);
return dataSource;
}
@Bean("DataSourceProd")
public DataSource dataSourceProd() throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser(user);
dataSource.setPassword(password);
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/ckqn");
// 5. 获取解析到的值
String value = stringValueResolver.resolveStringValue("${db.driverClass}");
dataSource.setDriverClass(value);
return dataSource;
}
// 6. 依赖注入
@Override
public void setEmbeddedValueResolver(StringValueResolver resolver) {
this.stringValueResolver=resolver;
}
}
3.外部资源文件
db.user=root
db.password=121788
db.driverClass=com.mysql.jdbc.Driver
4.测试
package com.jsxs.Test;
import com.jsxs.config.MainConfigOfProfile;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @Author Jsxs
* @Date 2023/8/17 21:31
* @PackageName:com.jsxs.Test
* @ClassName: IOCTest_Profile
* @Description: TODO
* @Version 1.0
*/
public class IOCTest_Profile {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfProfile.class);
for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
}
}
}
(2).根据环境注册bean (环境切换)
如何切换环境呢?
/**
* 切换环境的方式:
* 1、使用命令行动态参数:在虚拟机参数位置加载-Dspring.profiles.active=test(test是测试的环境标识)
* 2、代码的方式激活某种环境
*/
package com.jsxs.config;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.context.annotation.PropertySource;
import org.springframework.util.StringValueResolver;
import javax.sql.DataSource;
import java.beans.PropertyVetoException;
/**
* @Author Jsxs
* @Date 2023/8/17 20:59
* @PackageName:com.jsxs.config
* @ClassName: MainConfigOfProfile
* @Description: TODO @Profile:指定组件在哪个环境的情况下才能被注册到容器中。 @Bean: 任何环境下都可以被注册到容器中
* Spring为我们提供的可以根据当前环境,动态的激活和切换一系列bean的功能
* (1).开发环境、测试环境、生产环境
* (2).加了环境标识的bean,只有这个环境被激活的时候才能注册
* @Version 1.0
*/
@PropertySource("classpath:/db.properties") // 1. 因为要读取外部的文件,所以我们需要指定外部的文件的位置 ⭐
@Configuration
public class MainConfigOfProfile implements EmbeddedValueResolverAware { // 2.实现EmbeddedValueResolverAware解析器接口,这个接口主要是能够解析 ${} 和 #{}
@Value("${db.user}") // 3. 获取外部的文件,并赋值
private String user;
@Value("${db.password}")
private String password;
@Value("${db.driverClass}")
private String Driver;
// 4. 进行依赖注入的操作
private StringValueResolver stringValueResolver;
// @Profile("default") 假如我们写的是default,那么就会使用注解下方的数据源
@Profile("test") ⭐⭐
@Bean("DataSourceTest")
public DataSource dataSourceTest() throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser(user);
dataSource.setPassword(password);
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/demo1");
dataSource.setDriverClass(Driver);
return dataSource;
}
@Profile("dev")⭐⭐⭐
@Bean("DataSourceDev")
public DataSource dataSourceDev() throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser(user);
dataSource.setPassword(password);
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/library");
dataSource.setDriverClass(Driver);
return dataSource;
}
@Profile("prod")⭐⭐⭐
@Bean("DataSourceProd")
public DataSource dataSourceProd() throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser(user);
dataSource.setPassword(password);
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/ckqn");
// 5. 获取解析到的值
String value = stringValueResolver.resolveStringValue("${db.driverClass}");
dataSource.setDriverClass(value);
return dataSource;
}
// 6. 依赖注入
@Override
public void setEmbeddedValueResolver(StringValueResolver resolver) {
this.stringValueResolver = resolver;
}
}
package com.jsxs.Test;
import com.jsxs.config.MainConfigOfProfile;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @Author Jsxs
* @Date 2023/8/17 21:31
* @PackageName:com.jsxs.Test
* @ClassName: IOCTest_Profile
* @Description: TODO
* @Version 1.0
*/
public class IOCTest_Profile {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 1.指定环境 ⭐
applicationContext.getEnvironment().setActiveProfiles("test");
// 2.指定配置类 ⭐⭐
applicationContext.register(MainConfigOfProfile.class);
// 3.刷新容器 ⭐⭐⭐
applicationContext.refresh();
// 4.输出所有的组件
for (String beanDefinitionName : applicationContext.getBeanDefinitionNames()) {
System.out.println(beanDefinitionName);
}
}
}