1. @Configuration
- 声明这是一个配置类,替换以前配置文件
- @Configuration 中所有带 @Bean 注解的方法都会被动态代理,因此调用该方法返回的都是同一个实例
- 配置类必须以类的形式提供(不能是工厂方法返回的实例),允许通过生成子类在运行时增强(cglib 动态代理)
- 配置类不能是final 类(没法动态代理)
- 配置注解通常为了通过 @Bean注解生成 Spring 容器管理的类
- 配置类必须是非本地的(即不能在方法中声明,不能是 private)
- 任何嵌套配置类都必须声明为static
- @Bean方法可能不会反过来创建进一步的配置类(也就是返回的 bean 如果带有 @Configuration,也不会被特殊处理,只会作为普通的 bean)
@Bean 注解方法执行策略
@Configuration
public class MyBeanConfig {
@Bean
public Country country(){
return new Country();
}
@Bean
public UserInfo userInfo(){
return new UserInfo(country());
}
}
相信大多数人第一次看到上面userInfo() 中调用country()时,会认为这里的 Country和上面@Bean方法返回的 Country 可能不是同一个对象,因此可能会通过下面的方式来替代这种方式:
@Autowired
private Country country;
实际上不需要这么做,直接调用country()方法返回的是同一个实例
2. @ComponentScan 包扫描
如果是java8 可以使用可重复注解,以前可以使用ComponentScans、
2.1. 过滤规则
- FilterType.ANNOTATION:按照注解
- FilterType.ASSIGNABLE_TYPE:按照给定的类型
- FilterType.ASPECTJ:使用ASPECTJ表达式
- FilterType.REGEX:使用正则指定
- FilterType.CUSTOM:使用自定义规则
2.2. 包含/不包含扫描
@Configuration
@ComponentScan(value = "com.du",excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION,
classes = { Service.class, Controller.class})})
@ComponentScan(includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION,
classes = {Controller.class })},
useDefaultFilters = false )
public class ComponentScanTest {
}
2.3. 指定规则过滤
@Configuration
@ComponentScan(includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class}),
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {Account.class})
}, useDefaultFilters = false)
2.4. 自定义规则
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;
}
}
@Configuration
@ComponentScans(
value = {@ComponentScan(value="com.du",includeFilters = {
@Filter(type=FilterType.CUSTOM,classes={MyTypeFilter.class})
},useDefaultFilters = false)})
3. @Profile
基于多环境激活
使用命令行动态参数: 在虚拟机参数位置加载 -Dspring.profiles.active=test
@Configuration
public class ProfileShow implements EmbeddedValueResolverAware {
private StringValueResolver valueResolver;
private String driverClass;
@Profile("dev")
@Bean(name = "ds1")
public DataSource createDataSource1() {
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driverClass);
ds.setUrl("jdbc:mysql://120.48.14.129:3306/study");
ds.setUsername("root");
ds.setPassword("root");
return ds;
}
@Profile("prod")
@Bean(name = "ds2")
public DataSource createDataSource2() {
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driverClass);
ds.setUrl("jdbc:mysql://120.48.14.129:3306/study");
ds.setUsername("root");
ds.setPassword("root");
return ds;
}
@Override
public void setEmbeddedValueResolver(StringValueResolver resolver) {
this.valueResolver = resolver;
driverClass = valueResolver.resolveStringValue("${jdbc.driver}");
}
@Test
public void test(){
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext();
//1、创建一个applicationContext
//2、设置需要激活的环境
applicationContext.getEnvironment().setActiveProfiles("dev");
//3、注册主配置类
applicationContext.register(ProfileShow.class);
//4、启动刷新容器
applicationContext.refresh();
String[] beanNamesForType = applicationContext.getBeanNamesForType(DataSource.class);
System.out.println(beanNamesForType);
}
4. @Lookup
- 单例组件依赖非单例组件,非单例组件获取需要使用方法
- Autowired 获取的都是单的,包括对象里面包含对象
- 用于Get 方法上 目的 获取的对象的对象是多实例的
- @Bean 注解对象无效
@Component
public class Person {
public Person(){
System.out.println("person创建....");
}
private String name;
private Cat cat;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setCat(Cat cat) {
this.cat = cat;
}
@Lookup
public Cat getCat() {
return cat;
}
}
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Component
public class Cat {
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
@ComponentScan("com.du.anno.Lookup")
@Configuration
public class MainConfig {
}
public class AnnotationMainTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
Cat bean1 = applicationContext.getBean(Cat.class);
Cat bean2 = applicationContext.getBean(Cat.class);
//false
System.out.println(bean1 == bean2);
Person bean = applicationContext.getBean(Person.class);
Person bean3 = applicationContext.getBean(Person.class);
Cat cat = bean.getCat();
Cat cat1 = bean3.getCat();
//true
System.out.println(cat1 == cat);
}
}
5. @Scope
- 声明组件的作用范围
- SCOPE_PROTOTYPE
- SCOPE_SINGLETON
6. @Order
数字越小优先级越高,越先工作
7. @Primary
同类组件如果有多个,标注主组件
8. @Lazy
懒加载:容器启动不创建对象。
第一次使用(获取)Bean创建对象,并初始化
@Lazy
@Bean("person")
public Person person(){
System.out.println("给容器中添加Person....");
return new Person("张三", 25);
}
9. @DependsOn
组件之间声明依赖关系
10. @Indexed
加速注解,所有标注了 @Indexed 的组件,直接会启动快速加载