文章目录
spring进阶学习–给容器中注册组件的常用注解
1、注解:@Configuration & @Bean
@Configuration配置在类上,类被称为配置类,配置类和配置文件是一个性质的
@Bean配置在方法上,用于注册一个bean到spring容器中,bean的类型是返回值类型,id默认为方法名,可以通过value=""设置bean的id
配置类:
package com.markus.config;
import com.markus.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Author:markusZhang
* degree of proficiency:
* Date:Create in 2020/5/31 18:50
*/
@Configuration //告诉spring这是一个配置类 配置类==配置文件
public class SpringConfig {
// 使用注解Bean在spring容器中注册一个bean,类型是返回值类型,id默认是方法名
@Bean(value = "person")
public Person person01(){
return new Person("markus",20);
}
}
测试类:
package com.markus.test;
import com.markus.bean.Person;
import com.markus.config.SpringConfig;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* Author:markusZhang
* degree of proficiency:
* Date:Create in 2020/5/31 18:52
*/
public class SpringTest {
@Test
public void test(){
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
Person person = applicationContext.getBean(Person.class);
System.out.println(person);
String[] beanNamesForType = applicationContext.getBeanNamesForType(Person.class);
for(String beanName:beanNamesForType){
System.out.println(beanName);
}
}
}
测试结果:
2、注解:@ComponentScan
它的作用是进行包扫描,点进去它的源码看看
当我们在配置类上加上这样一个注解时,表明我们在启动容器的时候,需要将com.markus包下的文件注册到容器当中去
测试结果
我们来测试下excludeFilters
测试结果:就不包括service和controller了
includeFilter是一样的道理,将哪些配置扫描到容器当中去,这里就不测试了,但是需要注意的是,我们还需要配置一个useDefaultFilters=false,它默认是true的,如果为true的话,容器一启动就会扫描value指定的所有的包,我们需要修改它为false,然后指定哪些包需要被扫描的规则
扫描规则:
type:
- FilterType.ANNOTATION:按照注解
- FilterType.ASSIGNABLE_TYPE:按照给定的类型,也就是Bean的类
- FilterType.ASPECTJ:使用ASPECTJ表达式
- FilterType.REGEX:使用正则表达式
- FilterType.CUSTOM:自定义规则
着重来看下自定义规则:
使用方式
自定义类:
package com.markus.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:markusZhang
* degree of proficiency:
* Date:Create in 2020/5/31 20:23
*/
public class MyTypeFilter 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);
if(className.contains("er")){
return true;
}
return false;
}
}
3、注解:@Scope,调整作用域
spring容器,默认Bean都是单实例的,但是可以设置
默认单实例下,IoC容器启动会调用方法创建对象,放到IoC容器中,以后每次获取直接就是从容器中拿。
如果调成是多实例,IoC容器启动时,不会调用方法创建对象,当我们获取对象的时候,才会去调用方法去创建对象,多次获取就会多次调用
4、注解:@Lazy
懒加载:(延迟加载)
- 单实例Bean在启动容器的时候创建对象;
- 懒加载:容器启动的时候不会去创建对象,第一次使用(获取)Bean的时候去创建,并初始化;但是在以后调用的时候就不会再去创建了,因为是单实例bean
5、注解:@Conditional
@Conditional:按照一定的条件判断,满足条件给容器添加Bean
创建三个bean实例,后两个是用到@Conditional注解,我们需要实现两个Condition类
LinuxCondition :
package com.markus.condition;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
/**
* Author:markusZhang
* degree of proficiency:
* Date:Create in 2020/5/31 21:50
*/
public class LinuxCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
String property = context.getEnvironment().getProperty("os.name");
if(property.toLowerCase().contains("linux")){
return true;
}
return false;
}
}
WindowsCondition:
package com.markus.condition;
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.context.annotation.Conditional;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;
/**
* Author:markusZhang
* degree of proficiency:
* Date:Create in 2020/5/31 21:44
*/
public class WindowsCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// TODO: 2020/5/31 判断操作系统的类型来决定是否将Bean加入到容器当中
// 1、可以获得bean工厂,用于创建bean和装配bean的
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
// 2、可以获得类加载器
ClassLoader classLoader = context.getClassLoader();
// 3、获取BeanDefinitionRegistry,可以注册bean、删除bean等等
BeanDefinitionRegistry registry = context.getRegistry();
// 4、获取操作系统的环境
Environment environment = context.getEnvironment();
String property = environment.getProperty("os.name");
if(property.toLowerCase().contains("window")){
return true;
}
return false;
}
}
测试结果:
@Conditional不仅可以放到方法上,也可以放到类上进行统一设置
6、注解:@Import
@Import:快速给容器中导入一个组件,它可以配置在类上面
还可以导入多个组件
还可以实现类ImportSelector,来判断哪些需要注册到容器当中
自定义实现类:
package com.markus.condition;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
/**
* Author:markusZhang
* degree of proficiency:
* Date:Create in 2020/5/31 22:21
*/
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"com.markus.bean.Blue","com.markus.bean.Yellow"};
}
}
7、spring提供的FactoryBean(工厂Bean)
实现FactoryBean接口
package com.markus.bean;
import org.springframework.beans.factory.FactoryBean;
/**
* Author:markusZhang
* degree of proficiency:
* Date:Create in 2020/6/1 22:14
*/
public class ColorFactoryBean implements FactoryBean<Color> {
@Override
public Color getObject() throws Exception {
return new Color();
}
@Override
public Class<?> getObjectType() {
return Color.class;
}
@Override
public boolean isSingleton() {
return false;
}
}
将这个工厂Bean加入到容器中,
1、默认获取到的是工厂Bean调用getObject创建的对象
2、要获取工厂Bean本身,我们需要在ID前加 & 字符,会得到工厂Bean的对象
总结
给容器中注册组件:
- 通过包扫描+组件标注注解(@Controller、@Service、@Repository、@Component)[自己写的类]
- @Bean[导入的第三方包里面的组件]
- @Import[快速给容器中导入一个组件]