下面示例用到的依赖如下:
<!-- pom.xml -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
@Configuration
@Configuration
标注的类就是一个 Spring 配置类,配置类的作用就相当于之前我们使用的 Spring 配置文件。
示例
1、创建配置类,通过 @Configuration
注解标注一个类为配置类:
import org.springframework.context.annotation.Configuration;
/**
* 配置类
*/
@Configuration
public class MainConfig {
}
2、通过读取注解配置类来创建 IoC 容器:
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
@ComponentScan
@ComponentScan
注解的作用相当于在 Spring 配置文件中配置 <context:component-scan>
标签,扫描 bean 到 IoC 容器。
示例
1、创建测试 Service 类:
// com.springanno.service.UserService
import org.springframework.stereotype.Service;
@Service
public class UserService {
}
2、使用 @ComponentScan
注解:
// com.springanno.config.MainConfig
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* 配置类
*/
@Configuration
@ComponentScan("com.springanno")
public class MainConfig {
}
3、测试:
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
UserService bean = applicationContext.getBean(UserService.class);
System.out.println(bean);
/*
com.springanno.service.UserService@77e9807f
*/
相关属性
ComponentScan.Filter[] excludeFilters() default {}
:排除扫描匹配到的类。例:
excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class})}, // 不扫描指定注解标注的类
ComponentScan.Filter[] includeFilters() default {}
:仅扫描匹配到的类,要生效需同时指定 useDefaultFilters = false
。例:
includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Service.class})}, // 仅扫描指定注解标注的类
useDefaultFilters = false
@ComponentScan.Filter
用来指定过滤规则:
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Service.class}), // 过滤指定注解标注的类
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {UserService.class}), // 过滤给定类型的类
@ComponentScan.Filter(type = FilterType.ASPECTJ,pattern = {"com.springanno.service.*Service"}), // 通过 ASPECTJ 表达式过滤指定类
@ComponentScan.Filter(type = FilterType.REGEX, pattern ={".*.*Service"}), // 通过正则过滤指定类
还可自定义过滤规则,先自定义一个 TypeFilter
类:
// com.springanno.config.MyTypeFilter
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;
public class MyTypeFilter implements TypeFilter {
/**
* @param metadataReader 正在扫描的类的信息
* @param metadataReaderFactory 可获取其它类信息
* @return 如果返回 true ,说明当前扫描的类匹配成功
*/
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;
}
}
使用如下:
@ComponentScan.Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class}) // 自定义规则过滤
@Bean
@Bean
注解的作用相当于在 Spring 配置文件中配置 <bean>
标签。
示例 1:直接返回要注册的 bean
1、在配置类中使用 @Bean
注解注册一个 User 实例到 IoC 容器:
import com.springanno.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MainConfig {
/**
* 默认情况下方法名为 bean 的 id
* 返回值为加入到 IOC 容器的实例
* 可通过 @Bean 注解的 value 属性指定 bean 的 id
*
* <bean id="user1" class="com.springanno.pojo.User">
* <property name="name" value="张三"/>
* <property name="age" value="20"/>
* </bean>
*/
@Bean(value = "user1")
public User user(){
return new User("张三", 20);
}
}
2、测试:
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
Object user1 = applicationContext.getBean("user1");
System.out.println(user1);
/*
User{name='张三', age=20}
*/
示例 2:返回 FactoryBean
1、创建如下 FactoryBean
类:
// com.springanno.config.UserFactoryBean
import com.springanno.pojo.User;
import org.springframework.beans.factory.FactoryBean;
public class UserFactoryBean implements FactoryBean<User> {
/**
* 返回的对象将会添加到容器
*/
public User getObject() throws Exception {
return new User("ice",22);
}
/**
* 对象类型
*/
public Class<?> getObjectType() {
return User.class;
}
/**
* 是否单例
*/
public boolean isSingleton() {
return true;
}
}
2、使用 @Bean
注解注册 FactoryBean
实例到 IoC 容器:
// com.springanno.config.MainConfig
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MainConfig {
@Bean
public UserFactoryBean userFactoryBean(){
return new UserFactoryBean();
}
}
3、测试:
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
Object user = applicationContext.getBean("userFactoryBean");
System.out.println(user);
/*
mainConfig
userFactoryBean
User{name='ice', age=22}
*/
// 可以看到,我们获取的是 userFactoryBean,但实际上返回的是 userFactoryBean 对应实例的 getObject 方法的返回值
// 如果我们的确要获取 userFactoryBean 对应的实例,可通过 &id 这种方式获取:
UserFactoryBean userFactoryBean = (UserFactoryBean) applicationContext.getBean("&userFactoryBean");
System.out.println(userFactoryBean);
/*
com.springanno.config.UserFactoryBean@4461c7e3
*/
@Scope
@Scope
注解作用相当于在 <bean>
标签上的 scope
属性。
示例
1、使用 @Bean
注解注册 Bean 的同时使用 @Scope
注解:
// com.springanno.config.MainConfig
import com.springanno.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
@Configuration
public class MainConfig {
/**
* @Scope
* value 属性有如下可选值:
* singleton(默认): 单例。IOC 容器启动时就会调用方法创建对象放到容器,之后每次使用都是直接从容器中取。
* prototype : 多例。只有要使用该对象时才会调用该方法创建对象。
* request (web 环境): 一次请求。
* session (web 环境): 一次会话。
*/
@Scope("prototype")
@Bean
public User user(){
return new User("张三", 20);
}
}
2、测试:
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
Object user1 = applicationContext.getBean("user");
Object user2 = applicationContext.getBean("user");
System.out.println(user1==user2);
/*
false
*/
@Lazy
@Lazy
注解作用相当于在 <bean>
标签上配置属性 lazy-init="true"
,针对单实例 bean,控制容器启动时不创建对象,第一次获取该 bean 时才创建对象。。
示例
1、使用 @Bean
注册 bean 的同时使用 @Lazy
注解,标识改 bean 是一个懒加载的实例:
// com.springanno.config.MainConfig
import com.springanno.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
@Configuration
public class MainConfig {
@Lazy
@Bean
public User user(){
System.out.println("创建了");
return new User("张三", 20);
}
}
2、测试:
懒加载:ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
/*
[无任何输出]
*/
@Conditional
按照指定的条件进行判断,满足条件才在容器中注册 bean。
示例
当前操作系统为 Windows 时,我们注册一个 id
为 Windows 的 bean,当前系统为 Linux 时,注册一个 id
为 linux 的 bean
1、创建 Condition
类:
// com.springanno.condition.WindowsCondition
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;
/**
* 判断是否是 Windows 系统
*/
public class WindowsCondition implements Condition {
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
Environment environment = conditionContext.getEnvironment();
String osName = environment.getProperty("os.name").toLowerCase();
return osName.contains("windows");
}
}
// com.springanno.condition.LinuxCondition
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;
/**
* 判断是否是 Linux 系统
*/
public class LinuxCondition implements Condition {
/**
* @param conditionContext 判断条件能使用的上下文
* @param annotatedTypeMetadata 注解信息
*/
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
// 获取到容器使用的 BeanFactory
ConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory();
// 获取类加载器
ClassLoader classLoader = conditionContext.getClassLoader();
// 获取当前环境信息
Environment environment = conditionContext.getEnvironment();
// 获取 bean 定义的注册类
BeanDefinitionRegistry registry = conditionContext.getRegistry();
String osName = environment.getProperty("os.name").toLowerCase();
return osName.contains("linux");
}
}
2、注册 bean 时使用 @Condition
注解指定自定义的 Condition
类:
// com.springanno.config.MainConfig
import com.springanno.condition.LinuxCondition;
import com.springanno.condition.WindowsCondition;
import com.springanno.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MainConfig {
@Conditional({WindowsCondition.class})
@Bean
public User windows() {
return new User("windows", 20);
}
@Conditional({LinuxCondition.class})
@Bean
public User linux() {
return new User("linux", 3);
}
}
3、测试:
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
String[] beanNames = applicationContext.getBeanDefinitionNames();
for (String beanName : beanNames) {
System.out.println(beanName);
}
/*
mainConfig
windows
*/
// 当前是在 windows 下,所以可以看到只注册了 windows bean
@Import
@Import
的作用也是注册指定 bean 到 IoC 容器,只不过它相对来说更偏重于批量注册。它提供了下面几种注册 bean 到 IoC 容器的方式。
示例 1:直接注册指定 bean 到容器
1、指定要注册 bean 的类型:
// com.springanno.config.MainConfig
/**
* @Import 可以直接将注册指定 bean 到容器中,id 为 bean 的类全路径名
*/
@Import({User.class})
public class MainConfig {
}
2、测试:
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
/*
mainConfig
com.springanno.pojo.User
*/
示例 2:通过 ImportSelector 批量注册
1、定义 ImportSelector
类,在方法中返回要注册类的全路径名:
// com.springanno.config.MyImportSelector
import com.springanno.pojo.User;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.StringUtils;
import java.util.ArrayList;
import java.util.List;
public class MyImportSelector implements ImportSelector {
public String[] selectImports(AnnotationMetadata annotationMetadata) {
List<String> classNameList = new ArrayList<String>();
classNameList.add(User.class.getName());
return StringUtils.toStringArray(classNameList);
}
2、在 @Import
注解中指定 ImportSelector
类:
// com.springanno.config.MainConfig
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Configuration
/**
* MyImportSelector.selectImports() 方法返回的类的全路径列表,
* @Import 将会把这些全路径对应的类都注册到容器,id 为类的全路径名
*/
@Import({MyImportSelector.class})
public class MainConfig {
}
3、测试:
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
/*
mainConfig
com.springanno.pojo.User
*/
示例 3:通过 ImportBeanDefinitionRegistrar
手动定义 bean 信息注册 bean
1、创建如下 ImportBeanDefinitionRegistrar
类:
// com.springanno.config.MyImportBeanDefinitionRegistrar
import com.springanno.pojo.User;
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;
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
/**
*
* @param annotationMetadata 当前类注解信息
* @param beanDefinitionRegistry BeanDefinition 注册类
*
*/
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
// 判断 IOC 容器中是否已经注册了 user
boolean isContainsUser = beanDefinitionRegistry.containsBeanDefinition("user");
// 可以通过 beanDefinitionRegistry.registerBeanDefinition() 方法注册所有需要添加到容器中的 bean
if(!isContainsUser){
RootBeanDefinition beanDefinition = new RootBeanDefinition(User.class.getName());
// id=user
beanDefinitionRegistry.registerBeanDefinition("user", beanDefinition);
}
}
}
2、在 @Import
注解中指定 ImportBeanDefinitionRegistrar
类:
// com.springanno.config.MainConfig
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Configuration
/**
* @Import 会执行 MyImportBeanDefinitionRegistrar.registerBeanDefinitions(),在该方法中完成 bean 的注册
*/
@Import({MyImportBeanDefinitionRegistrar.class})
public class MainConfig {
}
3、测试:
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
/*
mainConfig
user
*/
评论区