(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); } }