上一节对配置类和注入Bean
的方式有一个最基本的认识,从这里开始讲解,想要往IOC
容器中添加我们自定义的类的方式一共有哪些
该注解需要配合@Configuration
标识的配置类上使用才会生效,它的作用是指定spring
的扫描包,则在扫描路径下的被特定注解标识的类就会被自动纳入到IOC
中,如我们熟知的@Repository
、@Service
、@Controller
等,而不需要每个都使用@Bean
注解一个个注入。
*属性详解
value
指定要扫描的包
excludeFilters
指定扫描的时候按照什么规则排除那些组件
includeFilters
指定扫描的时候只需要包含哪些组件,如果需要生效需要加入useDefaultFilters = false属性
FilterType.ANNOTATION
按照注解
FilterType.ASSIGNABLE_TYPE
按照给定的类
FilterType.ASPECTJ
使用ASPECTJ表达式
FilterType.REGEX
使用正则指定
FilterType.CUSTOM 使用自定义规则
UserController.java
来测试排除注解类型为@Controller
的类到容器中package com.ddf.spring.annotation.controller;
import org.springframework.stereotype.Controller;
/**
* @author DDf on 2018/7/19
* 该类的作用是为了测试排除所有@Controller注解的类不需要注册到IOC容器中,
* 详见{@link com.ddf.spring.annotation.configuration.AnnotationConfiguration}
*/
@Controller
public class UserController {
public UserController() {
System.out.println("UserController创建完成.................");
}
}
UserSerivce
,使用@Service
注解标注来测试扫描注入package com.ddf.spring.annotation.service;
import org.springframework.stereotype.Service;
/**
* @author DDf on 2018/7/19
* 默认@Scope为singleton,IOC容器启动会创建该bean的实例,并且以后再次使用不会重新创建新的实例
*/
@Service
public class UserService {
public UserService() {
System.out.println("UserService创建完成...................");
}
}
TypeFilter
接口的类,来自定义过滤规则ExcludeTypeFilter.java
package com.ddf.spring.annotation.configuration;
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 DDf on 2018/7/19
*/
public class ExcludeTypeFilter implements TypeFilter {
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
// 获取当前类注解的信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
// 获取当前正在扫描的类的类信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();
// 获取当前类资源(类的路径)
Resource resource = metadataReader.getResource();
String className = classMetadata.getClassName();
System.out.println("自定义扫描类规则当前扫描类为: "+ className);
// 这一块是return true 还是return false是有讲究的,比如把这个规则当做excludeFilters,那么返回true,则匹配的会过滤掉,如果把这个规则
// 应用到includeFilters,如果返回true,则是会加入到容器中
if (className.contains("ExcludeFilter")) {
return true;
}
return false;
}
}
ExcludeTypeFilter.java
规则的@Service
类,这个类本身应该会被纳入到容器中,在下面会演示如何根据自定义规则不纳入到容器中package com.ddf.spring.annotation.service;
import org.springframework.stereotype.Service;
/**
* @author DDf on 2018/7/19
* 该类的作用请参考{@link com.ddf.spring.annotation.configuration.ExcludeTypeFilter}是为了测试自定义规则决定是否导入某些bean
*/
@Service
public class ExcludeFilterService {
public ExcludeFilterService() {
System.out.println("ExcludeFilterService创建完成...............");
}
}
修改AnnotationConfiguration.java
package com.ddf.spring.annotation.configuration;
import com.ddf.spring.annotation.service.IncludeFilterService;
import com.ddf.spring.annotation.entity.User;
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;
/**
* @author DDf on 2018/7/19
* @Configuration 表明当前类是一个配置类
* @ComponentScan 指定扫描的包路径,并且配置了excludeFilters来排除注解类型为@Controller的不纳入容器中,
* 排除符合自定义ExcludeTypeFilter类中规则的类
*/
@Configuration
@ComponentScan(value = "com.ddf.spring.annotation", excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, value = Controller.class),
@ComponentScan.Filter(type=FilterType.CUSTOM, classes = ExcludeTypeFilter.class)
})
public class AnnotationConfiguration {
/**
* 注入一个Type为User(方法返回值)的bean,bean的名称为user(方法名)
* @return
*/
@Bean
public User user() {
return new User();
}
}
运行主启动类Application.java
,可以看到多注入了名称为userService
的bean
,标注了@Controller
的UserController
被排除纳入,同样满足ExcludeTypeFilter.java
定义规则的标注了@Service
的ExcludeFilterService.java
也被排除在外
-----------------------IOC容器初始化-------------------------
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.Application
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.configuration.ExcludeTypeFilter
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.controller.UserController
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.entity.User
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.service.ExcludeFilterService
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.service.IncludeFilterService
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.service.UserService
七月 19, 2018 11:53:53 下午 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
信息: JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
UserService创建完成...................
User创建完成...............
-----------------------IOC容器初始化完成-------------------------
bean name:org.springframework.context.annotation.internalConfigurationAnnotationProcessor, type: class org.springframework.context.annotation.ConfigurationClassPostProcessor
bean name:org.springframework.context.annotation.internalAutowiredAnnotationProcessor, type: class org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
bean name:org.springframework.context.annotation.internalRequiredAnnotationProcessor, type: class org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor
bean name:org.springframework.context.annotation.internalCommonAnnotationProcessor, type: class org.springframework.context.annotation.CommonAnnotationBeanPostProcessor
bean name:org.springframework.context.event.internalEventListenerProcessor, type: class org.springframework.context.event.EventListenerMethodProcessor
bean name:org.springframework.context.event.internalEventListenerFactory, type: class org.springframework.context.event.DefaultEventListenerFactory
bean name:annotationConfiguration, type: class com.ddf.spring.annotation.configuration.AnnotationConfiguration$$EnhancerBySpringCGLIB$$19c06e9b
bean name:userService, type: class com.ddf.spring.annotation.service.UserService
bean name:user, type: class com.ddf.spring.annotation.entity.User
Spring
初始化容器组件默认的scope
都是singleton
,即单实例。在容器初始化的时候就会把所有单实例的bean
初始化创建出来,以后每次在使用的时候不会重新创建一个对象,可以通过@Scope
来修改默认的作用域,作用域有以下属性
singleton 默认属性,单实例
prototype 启动创建,每次使用都是创建一个新的实例
request 基于HttpServletRequest
,每次请求创建一个实例
session 基于HttpSession
,每个session
作用域下使用同一个实例
Service
使用@Scope("prototype")
注解修饰, PrototypeScopeService.java
package com.ddf.spring.annotation.service;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
/**
* @author DDf on 2018/7/21
* 测试@Scope的作用域为prototype,每次使用该bean都会重新生成一个实例
*/
@Service
@Scope("prototype")
public class PrototypeScopeService {
public PrototypeScopeService() {
System.out.println("PrototypeScopeService创建完成。。。。。。。。");
}
}
UserService.java
来作为对比测试package com.ddf.spring.annotation.service;
import org.springframework.stereotype.Service;
/**
* @author DDf on 2018/7/19
* 默认@Scope为singleton,IOC容器启动会创建该bean的实例,并且以后再次使用不会重新创建新的实例
*/
@Service
public class UserService {
public UserService() {
System.out.println("UserService创建完成...................");
}
}
Application.java
,添加测试@Scope
的方法testPrototypeScopeService
package com.ddf.spring.annotation;
import com.ddf.spring.annotation.service.PrototypeScopeService;
import com.ddf.spring.annotation.service.UserService;
import com.ddf.spring.annotation.configuration.AnnotationConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @author DDf on 2018/7/19
*/
public class Application {
public static void main(String[] args) {
System.out.println("-----------------------IOC容器初始化-------------------------");
// 创建一个基于配置类启动的IOC容器,如果主配置类扫描包的路径下包含其他配置类,则其他配置类可以被自动识别
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AnnotationConfiguration.class);
System.out.println("-----------------------IOC容器初始化完成-------------------------");
// 获取当前IOC中所有bean的名称
String[] definitionNames = applicationContext.getBeanDefinitionNames();
// 打印当前IOC中对应名称的bean和bean的类型
for (String name : definitionNames) {
Object bean = applicationContext.getBean(name);
System.out.println("bean name:" + name + ", type: " + bean.getClass());
}
// 测试@Scope bean的作用域
testPrototypeScopeService(applicationContext);
}
/**
* 测试@Scope bean的作用域
* @param applicationContext
*/
public static void testPrototypeScopeService(ApplicationContext applicationContext) {
System.out.println("-----------------------测试@Scope-------------------------");
UserService userService = (UserService) applicationContext.getBean("userService");
UserService userService1 = applicationContext.getBean(UserService.class);
System.out.println("默认单实例bean UserService是否相等 " + (userService == userService1));
PrototypeScopeService prototypeScopeService = applicationContext.getBean(PrototypeScopeService.class);
PrototypeScopeService prototypeScopeService1 = applicationContext.getBean(PrototypeScopeService.class);
System.out.println("PrototypeScopeService prototype scope作用域是否相等: " + (prototypeScopeService == prototypeScopeService1));
}
}
-----------------------IOC容器初始化-------------------------
七月 21, 2018 6:52:36 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@5197848c: startup date [Sat Jul 21 18:52:36 CST 2018]; root of context hierarchy
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.Application
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.configuration.ExcludeTypeFilter
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.controller.UserController
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.entity.User
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.service.ExcludeFilterService
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.service.IncludeFilterService
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.service.PrototypeScopeService
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.service.UserService
七月 21, 2018 6:52:37 下午 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
信息: JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
UserService创建完成...................
User创建完成...............
-----------------------IOC容器初始化完成-------------------------
bean name:org.springframework.context.annotation.internalConfigurationAnnotationProcessor, type: class org.springframework.context.annotation.ConfigurationClassPostProcessor
bean name:org.springframework.context.annotation.internalAutowiredAnnotationProcessor, type: class org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
bean name:org.springframework.context.annotation.internalRequiredAnnotationProcessor, type: class org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor
bean name:org.springframework.context.annotation.internalCommonAnnotationProcessor, type: class org.springframework.context.annotation.CommonAnnotationBeanPostProcessor
bean name:org.springframework.context.event.internalEventListenerProcessor, type: class org.springframework.context.event.EventListenerMethodProcessor
bean name:org.springframework.context.event.internalEventListenerFactory, type: class org.springframework.context.event.DefaultEventListenerFactory
bean name:annotationConfiguration, type: class com.ddf.spring.annotation.configuration.AnnotationConfiguration$$EnhancerBySpringCGLIB$$5ee69aa7
PrototypeScopeService创建完成。。。。。。。。
bean name:prototypeScopeService, type: class com.ddf.spring.annotation.service.PrototypeScopeService
bean name:userService, type: class com.ddf.spring.annotation.service.UserService
bean name:user, type: class com.ddf.spring.annotation.entity.User
-----------------------测试@Scope开始-------------------------
默认单实例bean UserService是否相等 true
PrototypeScopeService创建完成。。。。。。。。
PrototypeScopeService创建完成。。。。。。。。
PrototypeScopeService prototype scope作用域是否相等: false
-----------------------测试@Scope结束-------------------------
默认情况下所有的单实例bean都会在容器启动的时候创建出来,使用的时候不会直接获取不会重复创建,但是可以通过@Lazy
注解来让容器启动的时候不创建某些类,而是等待第一次获取使用该类的时候才创建该Bean对象.
* 创建LazyBeanService.java
,使用@Lazy
和@Service
注解修饰来懒加载注入
package com.ddf.spring.annotation.service;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
/**
* @author DDf on 2018/7/21
* 测试单实例bean的@Lazy IOC容器启动的时候不创建该bean,只有到第一次获取的时候才创建
* 但当第一次使用这个bean的时候再创建,以后使用不再创建
*/
@Service
@Lazy
public class LazyBeanService {
public LazyBeanService() {
System.out.println("LazyBeanService创建完成...............");
}
}
Application.java
,增加测试懒加载的方法testLazyBeanService
,需要注意的是主启动类在以前的代码中为了测试方便,在启动后获取了所有预定义的bean
的名称然后获取打印了出来,为了更清楚的测试懒加载这一块的getBean()
需要注释掉,因为这里会牵扯到获取创建的问题package com.ddf.spring.annotation;
import com.ddf.spring.annotation.service.LazyBeanService;
import com.ddf.spring.annotation.service.PrototypeScopeService;
import com.ddf.spring.annotation.service.UserService;
import com.ddf.spring.annotation.configuration.AnnotationConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @author DDf on 2018/7/19
*/
public class Application {
public static void main(String[] args) {
System.out.println("-----------------------IOC容器初始化-------------------------");
// 创建一个基于配置类启动的IOC容器,如果主配置类扫描包的路径下包含其他配置类,则其他配置类可以被自动识别
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AnnotationConfiguration.class);
System.out.println("-----------------------IOC容器初始化完成-------------------------");
// 获取当前IOC中所有bean的名称,即使是懒加载类型的bean也会获取到
String[] definitionNames = applicationContext.getBeanDefinitionNames();
// 打印当前IOC中对应名称的bean和bean的类型
/*for (String name : definitionNames) {
// 这个会影响到测试懒加载的效果,如果需要测试懒加载,这行代码需要注释掉,因为getBean方法一旦调用则会初始化
Object bean = applicationContext.getBean(name);
System.out.println("bean name:" + name + ", type: " + bean.getClass());
}*/
// 测试@Scope bean的作用域
testPrototypeScopeService(applicationContext);
// 测试单实例bean的@Lazy懒加载
testLazyBeanService(applicationContext);
}
/**
* 测试@Scope bean的作用域
* @param applicationContext
*/
public static void testPrototypeScopeService(ApplicationContext applicationContext) {
System.out.println("-----------------------测试@Scope-------------------------");
UserService userService = (UserService) applicationContext.getBean("userService");
UserService userService1 = applicationContext.getBean(UserService.class);
System.out.println("默认单实例bean UserService是否相等 " + (userService == userService1));
PrototypeScopeService prototypeScopeService = applicationContext.getBean(PrototypeScopeService.class);
PrototypeScopeService prototypeScopeService1 = applicationContext.getBean(PrototypeScopeService.class);
System.out.println("PrototypeScopeService prototype scope作用域是否相等: " + (prototypeScopeService == prototypeScopeService1));
}
/**
* 测试单实例bean的懒加载,只有等使用的时候再创建实例。
* IOC容器启动后不会创建该bean的实例,如果是在该方法中才创建这个bean的实例,并且获得的两个bean是同一个的话,则测试通过。
*/
public static void testLazyBeanService(ApplicationContext applicationContext) {
System.out.println("---------------测试单实例bean的@Lazy懒加载----------------------");
LazyBeanService lazyBeanService = applicationContext.getBean(LazyBeanService.class);
LazyBeanService lazyBeanService1 = applicationContext.getBean(LazyBeanService.class);
System.out.println("lazyBeanService==lazyBeanService1?: " + (lazyBeanService == lazyBeanService1));
}
}
LazyBeanService
直到第一次获取的时候才被创建,并且是单实例-----------------------IOC容器初始化-------------------------
七月 21, 2018 9:29:55 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@5197848c: startup date [Sat Jul 21 21:29:55 CST 2018]; root of context hierarchy
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.Application
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.configuration.ExcludeTypeFilter
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.controller.UserController
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.entity.User
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.service.ExcludeFilterService
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.service.IncludeFilterService
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.service.LazyBeanService
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.service.PrototypeScopeService
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.service.UserService
七月 21, 2018 9:29:55 下午 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
信息: JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
UserService创建完成...................
User创建完成...............
-----------------------IOC容器初始化完成-------------------------
-----------------------测试@Scope开始-------------------------
默认单实例bean UserService是否相等 true
PrototypeScopeService创建完成。。。。。。。。
PrototypeScopeService创建完成。。。。。。。。
PrototypeScopeService prototype scope作用域是否相等: false
-----------------------测试@Scope结束-------------------------
---------------测试单实例bean的@Lazy懒加载开始----------------------
lazyBeanService==lazyBeanService1?: true
---------------测试单实例bean的@Lazy懒加载结束----------------------
Process finished with exit code 0
@Conditional
注解可以和导入Bean
的注解组合使用,导入Bean
的注解的作用是为容器中添加一个Bean
,而且只要使用了注解就无条件的导入,而@Conditional
注解可以指定一个类,该类必须实现org.springframework.context.annotation.Condition
接口,重写matches
方法返回true,则可以正常导入组件,但是如果返回false,则不能导入组件。而且该Condition
类中还可以额外注册一些组件,这对于某些组件是否导入是根据某些条件导入的,而且导入之后还需要附加某些组件来说是很有用处的。
现在来模拟一个场景,有两个需要动态导入的
Bean
,一个是DevelopmentBean
,该Bean
有一个附加Bean
为DevelopmentBeanLog
,同时还有一个Bean
名为ProductionBean
,该Bean
同样也有一个附加Bean
名为ProductionBeanLog
。现在的需求是根据不同的环境,如果是dev
环境则注册的DevelopmentBean
会生效,同时导入DevelopmentBeanLog
。如果当前环境是prd
,则注册的ProductionBean
会生效,同时会导入ProductionBeanLog
。环境的切换应该由外部配置文件来生效,但是为了方便测试,也为了不改代码就能够测试到两种不同的环境,所以使用当前时间的分钟,如果使偶数,则dev
环境生效,如果使奇数,则prd
环境生效;
* 创建DevelopmentBean.java
package com.ddf.spring.annotation.service;
/**
* @author DDf on 2018/7/21
*/
public class DevelopmentBean {
public DevelopmentBean() {
System.out.println("DevelopmentBean创建完成.............");
}
}
DevelopmentBeanLog.java
package com.ddf.spring.annotation.service;
/**
* @author DDf on 2018/7/21
*/
public class DevelopmentBeanLog {
public DevelopmentBeanLog() {
System.out.println("DevelopmentBeanLog创建完成...............");
}
}
ProductionBean.java
package com.ddf.spring.annotation.service;
/**
* @author DDf on 2018/7/21
*/
public class ProductionBean {
public ProductionBean() {
System.out.println("ProductionBean创建完成.............");
}
}
ProductionBeanLog.java
package com.ddf.spring.annotation.service;
/**
* @author DDf on 2018/7/21
*/
public class ProductionBeanLog {
public ProductionBeanLog() {
System.out.println("ProductionBeanLog创建完成...................");
}
}
dev
环境生效的判断条件和导入组件类DevelopmentProfileCondition.java
package com.ddf.spring.annotation.configuration;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.type.AnnotatedTypeMetadata;
import java.time.LocalDateTime;
/**
* @author DDf on 2018/7/21
* 创建根据条件来判断是否导入某些组件,该类需要配合@Condition注解,@Condition注解需要用在要导入容器的地方,与导入组件注解组合使用,如果当前类
* 返回true,则可以导入组件,反之,则不能。
*/
public class DevelopmentProfileCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// 获取到bean定义的注册类(可以获取bean,注册bean,删除预定义的bean名称)
BeanDefinitionRegistry registry = context.getRegistry();
// 获取IOC容器使用的beanfactory(可以获取bean的定义信息,可以获取到bean的定义注册类)
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
// 可以获取到环境变量
ConfigurableEnvironment environment = (ConfigurableEnvironment) context.getEnvironment();
// 根据当前时间的分钟动态切换环境变量的值
LocalDateTime localDateTime = LocalDateTime.now();
int minute = localDateTime.getMinute();
String profile;
if (minute % 2 == 0) {
profile = "dev";
} else {
profile = "prd";
}
System.out.println("DevelopmentProfileCondition profile: " + profile);
// 如果是dev环境,并且当前IOC容器中未定义ProductionBean则返回true,同时注册一个DevelopmentBeanLog
if ("dev".equals(profile)) {
if (!registry.containsBeanDefinition("ProductionBean")) {
RootBeanDefinition devServiceLogBean = new RootBeanDefinition(
"com.ddf.spring.annotation.bean.DevelopmentBeanLog");
registry.registerBeanDefinition("DevelopmentBeanLog", devServiceLogBean);
return true;
}
}
return false;
}
}
prd
环境生效的判断条件和导入组件类ProductionProfileCondition.java
package com.ddf.spring.annotation.configuration;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.type.AnnotatedTypeMetadata;
import java.time.LocalDateTime;
/**
* @author DDf on 2018/7/21
* 创建根据条件来判断是否导入某些组件,该类需要配合@Condition注解,@Condition注解需要用在要导入容器的地方,与导入组件注解组合使用,如果当前类
* 返回true,则可以导入组件,反之,则不能。
*/
public class ProductionProfileCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// 获取到bean定义的注册类(可以获取bean,注册bean,删除预定义的bean名称)
BeanDefinitionRegistry registry = context.getRegistry();
// 获取IOC容器使用的beanfactory(可以获取bean的定义信息,可以获取到bean的定义注册类)
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
// 可以获取到环境变量
ConfigurableEnvironment environment = (ConfigurableEnvironment) context.getEnvironment();
// 根据当前时间的分钟动态切换环境变量的值
LocalDateTime localDateTime = LocalDateTime.now();
int minute = localDateTime.getMinute();
String profile;
if (minute % 2 == 0) {
profile = "dev";
} else {
profile = "prd";
}
System.out.println("ProductionProfileCondition profile: " + profile);
// 如果是prd环境,并且当前IOC容器中未定义DevelopmentBean则返回true,同时注册一个ProductionBeanLog
if ("prd".equals(profile)) {
// 如果是prd环境,并且当前IOC容器中未定义DevelopmentBean则返回true,同时注册一个DevelopmentBeanLog
if (!registry.containsBeanDefinition("DevelopmentBean")) {
RootBeanDefinition prdServiceLogBean = new RootBeanDefinition(
"com.ddf.spring.annotation.bean.ProductionBeanLog");
registry.registerBeanDefinition("prdServiceLog", prdServiceLogBean);
return true;
}
}
return false;
}
}
AnnotationConfiguration
,使用@Bean
注解和@Condition
注解分别标注对应的类package com.ddf.spring.annotation.configuration;
import com.ddf.spring.annotation.bean.DevelopmentBean;
import com.ddf.spring.annotation.bean.ProductionBean;
import com.ddf.spring.annotation.entity.User;
import org.springframework.context.annotation.*;
import org.springframework.stereotype.Controller;
/**
* @author DDf on 2018/7/19
* @Configuration 表明当前类是一个配置类
* @ComponentScan 指定扫描的包路径,并且配置了excludeFilters来排除注解类型为@Controller的不纳入容器中,
* 排除符合自定义ExcludeTypeFilter类中规则的类
*/
@Configuration
@ComponentScan(value = "com.ddf.spring.annotation", excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, value = Controller.class),
@ComponentScan.Filter(type=FilterType.CUSTOM, classes = ExcludeTypeFilter.class)
})
public class AnnotationConfiguration {
/**
* 注入一个Type为User(方法返回值)的bean,bean的名称为user(方法名)
* @return
*/
@Bean
public User user() {
return new User();
}
/**
* 满足{@link DevelopmentProfileCondition} 这个类的条件返回true则当前Bean能够成功注入,反之不能
* @return
*/
@Bean
@Conditional({DevelopmentProfileCondition.class})
public DevelopmentBean DevelopmentBean() {
System.out.println("-------------------------测试@Conditional------------------");
return new DevelopmentBean();
}
/**
* 满足{@link ProductionProfileCondition} 这个类的条件返回true则当前Bean能够成功注入,反之不能
* @return
*/
@Bean
@Conditional({ProductionProfileCondition.class})
public ProductionBean ProductionBean() {
System.out.println("-------------------------测试@Conditional------------------");
return new ProductionBean();
}
}
Application.java
,控制台效果如下,通过控制台可以看到,虽然在配置类中定义了ProductionBean()
和DevelopmentBean()
两个方法,但是根据当前生效的环境,最终只会有一个被成功注入,另外一个就被忽略了,而且也可以看到在Condition
类中注册的类比方法体中注册的要早。-----------------------IOC容器初始化-------------------------
七月 21, 2018 10:54:48 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@5197848c: startup date [Sat Jul 21 22:54:48 CST 2018]; root of context hierarchy
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.Application
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.configuration.DevelopmentProfileCondition
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.configuration.ExcludeTypeFilter
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.configuration.ProductionProfileCondition
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.controller.UserController
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.entity.User
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.bean.DevelopmentBean
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.bean.DevelopmentBeanLog
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.service.ExcludeFilterService
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.service.IncludeFilterService
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.service.LazyBeanService
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.bean.ProductionBean
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.bean.ProductionBeanLog
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.service.PrototypeScopeService
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.service.UserService
DevelopmentProfileCondition profile: dev
ProductionProfileCondition profile: dev
七月 21, 2018 10:54:48 下午 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
信息: JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
UserService创建完成...................
User创建完成...............
DevelopmentBeanLog创建完成...............
-------------------------测试@Conditional------------------
DevelopmentBean创建完成.............
-----------------------IOC容器初始化完成-------------------------
bean name:org.springframework.context.annotation.internalConfigurationAnnotationProcessor, type: class org.springframework.context.annotation.ConfigurationClassPostProcessor
bean name:org.springframework.context.annotation.internalAutowiredAnnotationProcessor, type: class org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
bean name:org.springframework.context.annotation.internalRequiredAnnotationProcessor, type: class org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor
bean name:org.springframework.context.annotation.internalCommonAnnotationProcessor, type: class org.springframework.context.annotation.CommonAnnotationBeanPostProcessor
bean name:org.springframework.context.event.internalEventListenerProcessor, type: class org.springframework.context.event.EventListenerMethodProcessor
bean name:org.springframework.context.event.internalEventListenerFactory, type: class org.springframework.context.event.DefaultEventListenerFactory
bean name:annotationConfiguration, type: class com.ddf.spring.annotation.configuration.AnnotationConfiguration$$EnhancerBySpringCGLIB$$75d3a279
LazyBeanService创建完成...............
bean name:lazyBeanService, type: class com.ddf.spring.annotation.service.LazyBeanService
PrototypeScopeService创建完成。。。。。。。。
bean name:prototypeScopeService, type: class com.ddf.spring.annotation.service.PrototypeScopeService
bean name:userService, type: class com.ddf.spring.annotation.service.UserService
bean name:user, type: class com.ddf.spring.annotation.entity.User
bean name:DevelopmentBeanLog, type: class com.ddf.spring.annotation.bean.DevelopmentBeanLog
bean name:DevelopmentBean, type: class com.ddf.spring.annotation.bean.DevelopmentBean
-----------------------测试@Scope开始-------------------------
默认单实例bean UserService是否相等 true
PrototypeScopeService创建完成。。。。。。。。
PrototypeScopeService创建完成。。。。。。。。
PrototypeScopeService prototype scope作用域是否相等: false
-----------------------测试@Scope结束-------------------------
---------------测试单实例bean的@Lazy懒加载开始----------------------
lazyBeanService==lazyBeanService1?: true
---------------测试单实例bean的@Lazy懒加载结束----------------------
Process finished with exit code 0
该注解需要标注在带有
@Configuration
的类上,@Import的value
属性可以直接指定一个普通的java
类,即可直接导入组件,也可以实现ImportSelector
接口来导入一组组件,也可以实现ImportBeanDefinitionRegistrar
接口来获得当前注解信息,通过BeanDefinitionRegistry
来注册组件,这种方式可以指定导入的组件ID
ImportBean.java
,用来实验直接通过@Import
导入package com.ddf.spring.annotation.service;
/**
* @author DDf on 2018/7/30
*/
public class ImportBean {
public ImportBean() {
System.out.println("ImportBean创建完成(测试@Import导入组件)..........");
}
}
Configuration
类参考2.5.4@Import + ImportSelector
CustomImportSelector.java
实现ImportSelector
接口package com.ddf.spring.annotation.configuration;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
import java.util.Set;
/**
* @author DDf on 2018/7/30
* 测试和@Import一起使用通过ImportSelector来导入组件
*/
public class CustomImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
Set annotationTypes = importingClassMetadata.getAnnotationTypes();
// 做个简单的判断,如果标注了@Import注解的类上还有指定的另外一个注解,则导入一些组件,不可以自定义bean的名称
if (annotationTypes.contains("org.springframework.context.annotation.Import")) {
return new String[]{"com.ddf.spring.annotation.bean.ImportSelectorBean"};
}
return new String[0];
}
}
Configuration
类参考2.5.4@Import + ImportBeanDefinitionRegistrar
CustomImportBeanDefinitionRegistrar.java
实现ImportBeanDefinitionRegistrar
接口package com.ddf.spring.annotation.configuration;
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;
import java.util.Set;
/**
* @author DDf on 2018/7/31
* 测试使用@Import注解结合ImportBeanDefinitionRegistrar
*/
public class CustomImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
Set annotationTypes = annotationMetadata.getAnnotationTypes();
// 做个简单的判断,如果标注了@Import注解的类上还有指定的另外一个注解,则导入一些组件
if (annotationTypes.contains("org.springframework.context.annotation.Import")) {
// 通过BeanDefinitionRegistry导入一个组件
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(
"com.ddf.spring.annotation.bean.ImportBeanDefinitionRegistrarBean");
// 通过BeanDefinitionRegistry导入的组件可以自定义bean的名称
beanDefinitionRegistry.registerBeanDefinition("importBeanDefinitionRegistrarBean", rootBeanDefinition);
}
}
}
Configuration
类参考2.5.4AnnotationConfiguration.java
配置类,在前面的基础上加上@Import
的注解package com.ddf.spring.annotation.configuration;
import com.ddf.spring.annotation.bean.DevelopmentBean;
import com.ddf.spring.annotation.bean.ImportBean;
import com.ddf.spring.annotation.bean.ProductionBean;
import com.ddf.spring.annotation.entity.User;
import org.springframework.context.annotation.*;
import org.springframework.stereotype.Controller;
/**
* @author DDf on 2018/7/19
* @Configuration 表明当前类是一个配置类
* @ComponentScan 指定扫描的包路径,并且配置了excludeFilters来排除注解类型为@Controller的不纳入容器中,
* 排除符合自定义ExcludeTypeFilter类中规则的类
* @Import 导入组件,可以直接导入普通类,或者通过ImportSelector接口或者ImportBeanDefinitionRegistrar接口来自定义导入
*/
@Configuration
@ComponentScan(value = "com.ddf.spring.annotation", excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, value = Controller.class),
@ComponentScan.Filter(type = FilterType.CUSTOM, classes = ExcludeTypeFilter.class)
})
@Import(value = {ImportBean.class, CustomImportSelector.class, CustomImportBeanDefinitionRegistrar.class})
public class AnnotationConfiguration {
/**
* 注入一个Type为User(方法返回值)的bean,bean的名称为user(方法名)
*
* @return
*/
@Bean
public User user() {
return new User();
}
/**
* 测试@Conditional 满足{@link DevelopmentProfileCondition} 这个类的条件返回true则当前Bean能够成功注入,反之不能
*
* @return
*/
@Bean
@Conditional({DevelopmentProfileCondition.class})
public DevelopmentBean DevelopmentBean() {
return new DevelopmentBean();
}
/**
* 满足{@link ProductionProfileCondition} 这个类的条件返回true则当前Bean能够成功注入,反之不能
*
* @return
*/
@Bean
@Conditional({ProductionProfileCondition.class})
public ProductionBean ProductionBean() {
return new ProductionBean();
}
}
Application.java
,打印如下,可以看到ImportBean.java ImportSelectorBean ImportBeanDefinitionRegistrarBean
在IOC容器初始化的时候创建成功。 -----------------------IOC容器初始化-------------------------
八月 01, 2018 5:43:40 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@5197848c: startup date [Wed Aug 01 17:43:40 CST 2018]; root of context hierarchy
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.Application
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.configuration.CustomImportBeanDefinitionRegistrar
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.configuration.CustomImportSelector
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.configuration.DevelopmentProfileCondition
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.configuration.ExcludeTypeFilter
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.configuration.FactoryPrototypeBeanConfiguration
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.configuration.FactorySingletonBeanConfiguration
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.configuration.ProductionProfileCondition
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.controller.UserController
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.entity.User
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.bean.DevelopmentBean
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.bean.DevelopmentBeanLog
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.service.ExcludeFilterService
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.bean.FactoryPrototypeBean
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.bean.FactorySingletonBean
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.bean.ImportBean
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.bean.ImportBeanDefinitionRegistrarBean
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.bean.ImportSelectorBean
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.service.IncludeFilterService
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.service.LazyBeanService
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.bean.ProductionBean
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.bean.ProductionBeanLog
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.service.PrototypeScopeService
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.service.UserService
DevelopmentProfileCondition profile: prd
ProductionProfileCondition profile: prd
八月 01, 2018 5:43:40 下午 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
信息: JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
UserService创建完成...................
ImportBean创建完成(测试@Import导入组件)..........
ImportSelectorBean创建完成,测试@Import通过ImportSelector接口导入组件
User创建完成...............
ProductionBeanLog创建完成.......测试@Condition............
ProductionBean创建完成......测试@Condition.......
ImportBeanDefinitionRegistrarBean创建完成,测试@Import接口通过ImportBeanDefinitionRegistrar接口注入组件。。。。。
-----------------------IOC容器初始化完成-------------------------
bean name:org.springframework.context.annotation.internalConfigurationAnnotationProcessor, type: class org.springframework.context.annotation.ConfigurationClassPostProcessor
bean name:org.springframework.context.annotation.internalAutowiredAnnotationProcessor, type: class org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
bean name:org.springframework.context.annotation.internalRequiredAnnotationProcessor, type: class org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor
bean name:org.springframework.context.annotation.internalCommonAnnotationProcessor, type: class org.springframework.context.annotation.CommonAnnotationBeanPostProcessor
bean name:org.springframework.context.event.internalEventListenerProcessor, type: class org.springframework.context.event.EventListenerMethodProcessor
bean name:org.springframework.context.event.internalEventListenerFactory, type: class org.springframework.context.event.DefaultEventListenerFactory
bean name:annotationConfiguration, type: class com.ddf.spring.annotation.configuration.AnnotationConfiguration$$EnhancerBySpringCGLIB$$d7abd5ba
LazyBeanService创建完成...............
bean name:lazyBeanService, type: class com.ddf.spring.annotation.service.LazyBeanService
PrototypeScopeService创建完成。。。。。。。。
bean name:prototypeScopeService, type: class com.ddf.spring.annotation.service.PrototypeScopeService
bean name:userService, type: class com.ddf.spring.annotation.service.UserService
bean name:com.ddf.spring.annotation.bean.ImportBean, type: class com.ddf.spring.annotation.bean.ImportBean
bean name:com.ddf.spring.annotation.bean.ImportSelectorBean, type: class com.ddf.spring.annotation.bean.ImportSelectorBean
bean name:user, type: class com.ddf.spring.annotation.entity.User
bean name:prdServiceLog, type: class com.ddf.spring.annotation.bean.ProductionBeanLog
bean name:ProductionBean, type: class com.ddf.spring.annotation.bean.ProductionBean
bean name:importBeanDefinitionRegistrarBean, type: class com.ddf.spring.annotation.bean.ImportBeanDefinitionRegistrarBean
-----------------------测试@Scope开始-------------------------
默认单实例bean UserService是否相等 true
PrototypeScopeService创建完成。。。。。。。。
PrototypeScopeService创建完成。。。。。。。。
PrototypeScopeService prototype scope作用域是否相等: false
-----------------------测试@Scope结束-------------------------
---------------测试单实例bean的@Lazy懒加载开始----------------------
lazyBeanService==lazyBeanService1?: true
---------------测试单实例bean的@Lazy懒加载结束----------------------
Process finished with exit code 0
FactoryBean
接口注入组件通过FactoryBean工厂注册组件,该类本身需要注册到IOC容器中,如在类上标注
@Component
等或者使用@Bean
注解,实际在IOC中注册的组件为FactoryBean中接口的方法来决定而非FactoryBean
类本身,通过这种方式创建的组件可以isSingleton
方法来决定组件是否为单实例,如果为单实例则同时该Bean
是以懒加载的方式注册的
FactorySingletonBean.java
,用来演示单实例beanpackage com.ddf.spring.annotation.service;
/**
* @author DDf on 2018/7/31
* 该类用于测试使用FactoryBean来注册单实例组件
*/
public class FactorySingletonBean {
public FactorySingletonBean() {
System.out.println("FactorySingletonBean创建完成。。。。,测试通过FactoryBean来注册单实例组件。。。。");
}
}
FactorySingletonBean
的FactoryBean
接口,FactorySingletonBeanConfiguration.java
package com.ddf.spring.annotation.configuration;
import com.ddf.spring.annotation.bean.FactorySingletonBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.stereotype.Component;
/**
* @author DDf on 2018/8/1
* 通过FactoryBean工厂注册组件,该类本身需要注册到IOC容器中
* 实际在IOC中注册的组件为FactoryBean中接口的方法来决定
*/
// @Component
public class FactorySingletonBeanConfiguration implements FactoryBean<FactorySingletonBean> {
/**
* 要注册的组件
* @return
*/
@Override
public FactorySingletonBean getObject() {
return new FactorySingletonBean();
}
/**
* 要注册的组件类型
* @return
*/
@Override
public Class> getObjectType() {
return FactorySingletonBean.class;
}
/**
* 要注册的组件是否是单实例
* @return
*/
@Override
public boolean isSingleton() {
return true;
}
}
FactoryPrototypeBean.java
,用来演示非单实例bean
package com.ddf.spring.annotation.service;
/**
* @author DDf on 2018/8/1
* 该类用于测试使用FactoryBean来注册每个请求重新创建组件
*/
public class FactoryPrototypeBean {
public FactoryPrototypeBean() {
System.out.println("FactoryPrototypeBean创建完成....,测试通过FactoryBean来注册Prototype组件。。。。");
}
}
FactoryPrototypeBean
的FactoryBean
接口FactoryPrototypeBeanConfiguration.java
package com.ddf.spring.annotation.configuration;
import com.ddf.spring.annotation.bean.FactoryPrototypeBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.stereotype.Component;
/**
* @author DDf on 2018/8/1
* 通过FactoryBean工厂注册组件,该类本身需要注册到IOC容器中
* 实际在IOC中注册的组件为FactoryBean中接口的方法来决定
*/
// @Component
public class FactoryPrototypeBeanConfiguration implements FactoryBean<FactoryPrototypeBean> {
/**
* 要注册的组件
* @return
*/
@Override
public FactoryPrototypeBean getObject() {
return new FactoryPrototypeBean();
}
/**
* 要注册的组件类型
* @return
*/
@Override
public Class> getObjectType() {
return FactoryPrototypeBean.class;
}
/**
* 要注册的组件是否是单实例
* @return
*/
@Override
public boolean isSingleton() {
return false;
}
}
AnnotationConfiguration.java
,使用配置类的方式将FactoryPrototypeBeanConfiguration
和FactorySingletonBeanConfiguration
两个FactoryBean
接口注册到容器中package com.ddf.spring.annotation.configuration;
import com.ddf.spring.annotation.bean.DevelopmentBean;
import com.ddf.spring.annotation.bean.ImportBean;
import com.ddf.spring.annotation.bean.ProductionBean;
import com.ddf.spring.annotation.entity.User;
import org.springframework.context.annotation.*;
import org.springframework.stereotype.Controller;
/**
* @author DDf on 2018/7/19
* @Configuration 表明当前类是一个配置类
* @ComponentScan 指定扫描的包路径,并且配置了excludeFilters来排除注解类型为@Controller的不纳入容器中,
* 排除符合自定义ExcludeTypeFilter类中规则的类
* @Import 导入组件,可以直接导入普通类,或者通过ImportSelector接口或者ImportBeanDefinitionRegistrar接口来自定义导入
*/
@Configuration
@ComponentScan(value = "com.ddf.spring.annotation", excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, value = Controller.class),
@ComponentScan.Filter(type = FilterType.CUSTOM, classes = ExcludeTypeFilter.class)
})
@Import(value = {ImportBean.class, CustomImportSelector.class, CustomImportBeanDefinitionRegistrar.class})
public class AnnotationConfiguration {
/**
* 注入一个Type为User(方法返回值)的bean,bean的名称为user(方法名)
*
* @return
*/
@Bean
public User user() {
return new User();
}
/**
* 测试@Conditional 满足{@link DevelopmentProfileCondition} 这个类的条件返回true则当前Bean能够成功注入,反之不能
*
* @return
*/
@Bean
@Conditional({DevelopmentProfileCondition.class})
public DevelopmentBean DevelopmentBean() {
return new DevelopmentBean();
}
/**
* 满足{@link ProductionProfileCondition} 这个类的条件返回true则当前Bean能够成功注入,反之不能
*
* @return
*/
@Bean
@Conditional({ProductionProfileCondition.class})
public ProductionBean ProductionBean() {
return new ProductionBean();
}
/**
* 使用FactoryBean工厂来注册组件
* @return
*/
@Bean
public FactoryPrototypeBeanConfiguration factoryPrototypeBeanConfiguration() {
return new FactoryPrototypeBeanConfiguration();
}
/**
* 使用FactoryBean工厂来注册组件
* @return
*/
@Bean
public FactorySingletonBeanConfiguration factorySingletonBeanConfiguration() {
return new FactorySingletonBeanConfiguration();
}
}
Application.java
,用来验证FactoryBean
创建bean
的作用域package com.ddf.spring.annotation;
import com.ddf.spring.annotation.service.*;
import com.ddf.spring.annotation.configuration.AnnotationConfiguration;
import com.ddf.spring.annotation.configuration.FactoryPrototypeBeanConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @author DDf on 2018/7/19
*/
public class Application {
public static void main(String[] args) {
System.out.println("-----------------------IOC容器初始化-------------------------");
// 创建一个基于配置类启动的IOC容器,如果主配置类扫描包的路径下包含其他配置类,则其他配置类可以被自动识别
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AnnotationConfiguration.class);
System.out.println("-----------------------IOC容器初始化完成-------------------------\n");
// 获取当前IOC中所有bean的名称,即使是懒加载类型的bean也会获取到
String[] definitionNames = applicationContext.getBeanDefinitionNames();
// 打印当前IOC中对应名称的bean和bean的类型
for (String name : definitionNames) {
// 这个会影响到测试懒加载的效果,如果需要测试懒加载,这行代码需要注释掉,因为getBean方法一旦调用则会初始化
Object bean = applicationContext.getBean(name);
System.out.println("bean name:" + name + ", type: " + bean.getClass());
}
// 测试@Scope bean的作用域
testPrototypeScopeService(applicationContext);
// 测试单实例bean的@Lazy懒加载
testLazyBeanService(applicationContext);
// 测试FactoryBean接口导入单实例与Prototype作用域的组件
testFactoryBeanPrototypeBean(applicationContext);
}
/**
* 测试@Scope bean的作用域
*
* @param applicationContext
*/
public static void testPrototypeScopeService(ApplicationContext applicationContext) {
System.out.println("\n-----------------------测试@Scope开始-------------------------");
UserService userService = (UserService) applicationContext.getBean("userService");
UserService userService1 = applicationContext.getBean(UserService.class);
System.out.println("默认单实例bean UserService是否相等 " + (userService == userService1));
PrototypeScopeService prototypeScopeService = applicationContext.getBean(PrototypeScopeService.class);
PrototypeScopeService prototypeScopeService1 = applicationContext.getBean(PrototypeScopeService.class);
System.out.println("PrototypeScopeService prototype scope作用域是否相等: " + (prototypeScopeService == prototypeScopeService1));
System.out.println("-----------------------测试@Scope结束-------------------------\n");
}
/**
* 测试单实例bean的懒加载,只有等使用的时候再创建实例。
* IOC容器启动后不会创建该bean的实例,如果是在该方法中才创建这个bean的实例,并且获得的两个bean是同一个的话,则测试通过。
*/
public static void testLazyBeanService(ApplicationContext applicationContext) {
System.out.println("\n---------------测试单实例bean的@Lazy懒加载开始----------------------");
LazyBeanService lazyBeanService = applicationContext.getBean(LazyBeanService.class);
LazyBeanService lazyBeanService1 = applicationContext.getBean(LazyBeanService.class);
System.out.println("lazyBeanService==lazyBeanService1?: " + (lazyBeanService == lazyBeanService1));
System.out.println("---------------测试单实例bean的@Lazy懒加载结束----------------------\n");
}
/**
* 测试通过FactoryBean接口导入单实例与Prototype作用域的组件,根据打印可以看出FactoryBean创建的单实例Bean都是懒加载的
* @param applicationContext
*/
public static void testFactoryBeanPrototypeBean(ApplicationContext applicationContext) {
System.out.println("\n----------测试通过FactoryBean注册单实例和Prototype作用域的组件开始----------");
FactorySingletonBean factorySingletonBean = applicationContext.getBean(FactorySingletonBean.class);
FactorySingletonBean factorySingletonBean1 = applicationContext.getBean(FactorySingletonBean.class);
FactoryPrototypeBean factoryPrototypeBean = applicationContext.getBean(FactoryPrototypeBean.class);
FactoryPrototypeBean factoryPrototypeBean1 = applicationContext.getBean(FactoryPrototypeBean.class);
System.out.println("单实例factorySingletonBean==factorySingletonBean1?" + (factorySingletonBean==factorySingletonBean1));
System.out.println("Prototype作用域factoryPrototypeBean==factoryPrototypeBean1?" + (factoryPrototypeBean==factoryPrototypeBean1));
System.out.println("----------测试通过FactoryBean注册单实例和Prototype作用域的组件结束----------\n");
}
}
IOC
容器创建的时候并没有创建,但是在获得所有定义的bean打印的时候才创建-----------------------IOC容器初始化-------------------------
八月 01, 2018 6:06:46 下午 org.springframework.context.annotation.AnnotationConfigApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@5197848c: startup date [Wed Aug 01 18:06:46 CST 2018]; root of context hierarchy
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.Application
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.configuration.CustomImportBeanDefinitionRegistrar
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.configuration.CustomImportSelector
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.configuration.DevelopmentProfileCondition
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.configuration.ExcludeTypeFilter
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.configuration.FactoryPrototypeBeanConfiguration
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.configuration.FactorySingletonBeanConfiguration
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.configuration.ProductionProfileCondition
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.controller.UserController
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.entity.User
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.bean.DevelopmentBean
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.bean.DevelopmentBeanLog
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.service.ExcludeFilterService
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.bean.FactoryPrototypeBean
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.bean.FactorySingletonBean
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.bean.ImportBean
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.bean.ImportBeanDefinitionRegistrarBean
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.bean.ImportSelectorBean
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.service.IncludeFilterService
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.service.LazyBeanService
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.bean.ProductionBean
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.bean.ProductionBeanLog
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.service.PrototypeScopeService
自定义扫描类规则当前扫描类为: com.ddf.spring.annotation.service.UserService
DevelopmentProfileCondition profile: dev
ProductionProfileCondition profile: dev
八月 01, 2018 6:06:46 下午 org.springframework.beans.factory.support.DefaultListableBeanFactory registerBeanDefinition
信息: Overriding bean definition for bean 'factoryPrototypeBeanConfiguration' with a different definition: replacing [Generic bean: class [com.ddf.spring.annotation.configuration.FactoryPrototypeBeanConfiguration]; scope=singleton; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in file [D:\dev-tools\idea_root\spring-annotation\target\classes\com\ddf\spring\annotation\configuration\FactoryPrototypeBeanConfiguration.class]] with [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=annotationConfiguration; factoryMethodName=factoryPrototypeBeanConfiguration; initMethodName=null; destroyMethodName=(inferred); defined in com.ddf.spring.annotation.configuration.AnnotationConfiguration]
八月 01, 2018 6:06:46 下午 org.springframework.beans.factory.support.DefaultListableBeanFactory registerBeanDefinition
信息: Overriding bean definition for bean 'factorySingletonBeanConfiguration' with a different definition: replacing [Generic bean: class [com.ddf.spring.annotation.configuration.FactorySingletonBeanConfiguration]; scope=singleton; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in file [D:\dev-tools\idea_root\spring-annotation\target\classes\com\ddf\spring\annotation\configuration\FactorySingletonBeanConfiguration.class]] with [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=annotationConfiguration; factoryMethodName=factorySingletonBeanConfiguration; initMethodName=null; destroyMethodName=(inferred); defined in com.ddf.spring.annotation.configuration.AnnotationConfiguration]
八月 01, 2018 6:06:47 下午 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
信息: JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
UserService创建完成...................
ImportBean创建完成(测试@Import导入组件)..........
ImportSelectorBean创建完成,测试@Import通过ImportSelector接口导入组件
User创建完成...............
DevelopmentBeanLog创建完成.......测试@Condition........
DevelopmentBean创建完成.....测试@Condition........
ImportBeanDefinitionRegistrarBean创建完成,测试@Import接口通过ImportBeanDefinitionRegistrar接口注入组件。。。。。
-----------------------IOC容器初始化完成-------------------------
bean name:org.springframework.context.annotation.internalConfigurationAnnotationProcessor, type: class org.springframework.context.annotation.ConfigurationClassPostProcessor
bean name:org.springframework.context.annotation.internalAutowiredAnnotationProcessor, type: class org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor
bean name:org.springframework.context.annotation.internalRequiredAnnotationProcessor, type: class org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor
bean name:org.springframework.context.annotation.internalCommonAnnotationProcessor, type: class org.springframework.context.annotation.CommonAnnotationBeanPostProcessor
bean name:org.springframework.context.event.internalEventListenerProcessor, type: class org.springframework.context.event.EventListenerMethodProcessor
bean name:org.springframework.context.event.internalEventListenerFactory, type: class org.springframework.context.event.DefaultEventListenerFactory
bean name:annotationConfiguration, type: class com.ddf.spring.annotation.configuration.AnnotationConfiguration$$EnhancerBySpringCGLIB$$7e17d64c
FactoryPrototypeBean创建完成....,测试通过FactoryBean来注册单实例组件。。。。
bean name:factoryPrototypeBeanConfiguration, type: class com.ddf.spring.annotation.bean.FactoryPrototypeBean
FactorySingletonBean创建完成。。。。,测试通过FactoryBean来注册单实例组件。。。。
bean name:factorySingletonBeanConfiguration, type: class com.ddf.spring.annotation.bean.FactorySingletonBean
LazyBeanService创建完成...............
bean name:lazyBeanService, type: class com.ddf.spring.annotation.service.LazyBeanService
PrototypeScopeService创建完成。。。。。。。。
bean name:prototypeScopeService, type: class com.ddf.spring.annotation.service.PrototypeScopeService
bean name:userService, type: class com.ddf.spring.annotation.service.UserService
bean name:com.ddf.spring.annotation.bean.ImportBean, type: class com.ddf.spring.annotation.bean.ImportBean
bean name:com.ddf.spring.annotation.bean.ImportSelectorBean, type: class com.ddf.spring.annotation.bean.ImportSelectorBean
bean name:user, type: class com.ddf.spring.annotation.entity.User
bean name:DevelopmentBeanLog, type: class com.ddf.spring.annotation.bean.DevelopmentBeanLog
bean name:DevelopmentBean, type: class com.ddf.spring.annotation.bean.DevelopmentBean
bean name:importBeanDefinitionRegistrarBean, type: class com.ddf.spring.annotation.bean.ImportBeanDefinitionRegistrarBean
-----------------------测试@Scope开始-------------------------
默认单实例bean UserService是否相等 true
PrototypeScopeService创建完成。。。。。。。。
PrototypeScopeService创建完成。。。。。。。。
PrototypeScopeService prototype scope作用域是否相等: false
-----------------------测试@Scope结束-------------------------
---------------测试单实例bean的@Lazy懒加载开始----------------------
lazyBeanService==lazyBeanService1?: true
---------------测试单实例bean的@Lazy懒加载结束----------------------
----------测试通过FactoryBean注册单实例和Prototype作用域的组件开始----------
FactoryPrototypeBean创建完成....,测试通过FactoryBean来注册单实例组件。。。。
FactoryPrototypeBean创建完成....,测试通过FactoryBean来注册单实例组件。。。。
单实例factorySingletonBean==factorySingletonBean1?true
Prototype作用域factoryPrototypeBean==factoryPrototypeBean1?false
----------测试通过FactoryBean注册单实例和Prototype作用域的组件结束----------
Process finished with exit code 0