1.基于spring5
代码的目录结构,以下代码都是基于此:
其它类都加了注解除Person:
@Repository
public class OrderDao {
}
@Service
public class SampleService {
}
@Controller
public class TestController {
}
启动类SampleTest类代码:
public class SampleTest {
@Test
public void test01(){
AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(SampleConfig.class);
String[] names = app.getBeanDefinitionNames();
for (String name : names) {
System.out.println(name);
}
}
}
@Bean
这个是最简单注入方式(配合@Scope可配置单例,多例/@lazy懒加载):
@lazy懒加载
@Scope可配置单例
@Configuration
public class Config {
//给容器中注册一个bean,类型为返回值的类型
@Bean
public Person person(){
return new Person();
}
}
@ComponentScan先来说说这个scan的其它几个功能:
1.导入包下指定类:
@Configuration
@ComponentScan(value="com.demo.service",includeFilters = {
//包含的类型,可以是注解,class,正则,自定义,等等
@Filter(type = FilterType.ANNOTATION,classes = {Controller.class})
},
//注意这个属性要改false(是否使用默认过滤器)
useDefaultFilters = false)
public class SampleConfig {
}
打印:
看一下为useDefaultFilters=true的结果:
注意使用includeFilters时,useDefaultFilters必需为false原因为:
org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider#registerDefaultFilters此类中(追到此类的代码,可以再这个方法打断点自己看一下debug的线程调用栈能看到调用顺序):
protected void registerDefaultFilters() {
//导入Component标注的类
this.includeFilters.add(new AnnotationTypeFilter(Component.class));
ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
try {
this.includeFilters.add(new AnnotationTypeFilter(
((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
logger.trace("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
}
catch (ClassNotFoundException ex) {
// JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.
}
try {
this.includeFilters.add(new AnnotationTypeFilter(
((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
logger.trace("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip.
}
}
@service/@controller/@Repository都继承了Component所以会
2.排除包下部分类或指定类:
@Configuration
@ComponentScan(value="com.demo",excludeFilters = {
//排除的类型,可以是注解,class,正则,自定义,等等
@Filter(type = FilterType.ANNOTATION,classes = {Controller.class})
},useDefaultFilters = true)
public class SampleConfig {
}
打印结果(此时useDefaultFilters就可以为true了):
3.自定义导入或排除
@Configuration
@ComponentScan(value="com.demo",excludeFilters = {
//包含的类型,可以是注解,class,正则,自定义,等等
@Filter(type = FilterType.CUSTOM,classes = {CustomTypeFilter.class})
},useDefaultFilters = false)
public class SampleConfig {
}
/**
*在此类的此match方法中写自己的逻辑,返回true或false代表是否满足条件
*/
public class CustomTypeFilter implements TypeFilter {
/**
* @param metadataReader 读取当前正在扫描的类信息
* @param metadataReaderFactory 可以读取到任何其它类信息
*/
@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 false;
}
}
@Conditional条件注入
public class WinCondition implements Condition {
/**
* @param context 判断条件可以使用的上下文(环境)
* @param metadata 注解信息
*/
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
//能获取到IOC容器正在使用的BeanFactory
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
//获取当前环境变量(包括操作系统的类型)
Environment environment = context.getEnvironment();
String property = environment.getProperty("os.name");
if(property.contains("Windows")) return true;
return false;
}
}
@Configuration
public class SampleConfig {
@Conditional(WinCondition.class)
@Bean
public Person person(){
return new Person();
}
}
返回:
如果想为不为windows自己改一下启动的注入参数即可测试。
@import[快速给容器注入一个组件]相对于@bean有点简单
1.注入的bean的id为全类名(带包的)
@Configuration
@Import(value={Person.class})
public class SampleConfig {
}
返回:
2.ImportSelector:是一个接口,返回需要导入的全类名数组
public class SampleImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
//这里写逻辑,返回需要的class全类名数组,切记不可返回null不然会报异常
return new String[]{"com.demo.model.demo3.model.Person"};
}
}
@Configuration
@Import(value={SampleImportSelector.class})
public class SampleConfig {
}
此org.springframework.context.annotation.ConfigurationClassParser#processImports代码没有做null校验:
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, boolean checkForCircularImports) {
if (importCandidates.isEmpty()) {
return;
}
if (checkForCircularImports && isChainedImportOnStack(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
}
else {
this.importStack.push(configClass);
try {
for (SourceClass candidate : importCandidates) {
if (candidate.isAssignable(ImportSelector.class)) {
// Candidate class is an ImportSelector -> delegate to it to determine imports
Class<?> candidateClass = candidate.loadClass();
ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
ParserStrategyUtils.invokeAwareMethods(
selector, this.environment, this.resourceLoader, this.registry);
if (selector instanceof DeferredImportSelector) {
this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
}
else {
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
//这里没有做null的校验,但可对空数组做处理
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
processImports(configClass, currentSourceClass, importSourceClasses, false);
}
}
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
// Candidate class is an ImportBeanDefinitionRegistrar ->
// delegate to it to register additional bean definitions
Class<?> candidateClass = candidate.loadClass();
ImportBeanDefinitionRegistrar registrar =
BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
ParserStrategyUtils.invokeAwareMethods(
registrar, this.environment, this.resourceLoader, this.registry);
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
else {
// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
// process it as an @Configuration class
this.importStack.registerImport(
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
processConfigurationClass(candidate.asConfigClass(configClass));
}
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to process import candidates for configuration class [" +
configClass.getMetadata().getClassName() + "]", ex);
}
finally {
this.importStack.pop();
}
}
}
3.ImportBeanDefinitionRegistrar是一个接口,用于自身业务特定需求(可对Bean的BeanDefinition进行定义)
public class SampleImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
/**
* @param importingClassMetadata 当前类的注解信息
* @param registry BeanDefinition注册类
* 把所有需要添加到容器的bean加入
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
boolean b = registry.containsBeanDefinition("com.demo.model.demo3.model.Pig");
boolean b1 = registry.containsBeanDefinition("com.demo.model.demo3.model.Person");
//如果b和b1同时存在于IOC容器中时,给bean进行封装
if(b && b1){
RootBeanDefinition beanDefinition = new RootBeanDefinition(Dog.class);
registry.registerBeanDefinition("dog",beanDefinition);
}
}
}
@Configuration
@Import(value={SampleImportSelector.class, SampleImportBeanDefinitionRegistrar.class})
public class SampleConfig {
}
FactoryBean接口
1.FactoryBean与BeanFactory的区别?
FactoryBean: 是生成java对象,把对象转为spring管理的bean
BeanFacotry: 从spring管理的bean中取出实例bean
2.用法
public class SampleFactoryBean implements FactoryBean<Person> {
//返回实例bean
@Override
public Person getObject() throws Exception {
return new Person();
}
//返回class
@Override
public Class<?> getObjectType() {
return Person.class;
}
//是否单例
public boolean isSingleton() {
return true;
}
}
@Configuration
public class SampleConfig {
@Bean
public SampleFactoryBean sampleFactoryBean(){
return new SampleFactoryBean();
}
}
public class SampleTest {
@Test
public void test01(){
AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(SampleConfig.class);
String[] names = app.getBeanDefinitionNames();
//factoryBean正常直接取,取的是Person
Object bean = app.getBean("sampleFactoryBean");
System.out.println(bean);
//factoryBean在取值方面有说法:beanName前加"&"取的是sampleFactoryBean
Object bean2 = app.getBean("&sampleFactoryBean");
System.out.println(bean2);
for (String name : names) {
System.out.println(name);
}
}
}
注意实FactoryBean在getBean时要注意“&”的用法