/**
* @author wy
* describe `@ComponentScan`注解,包扫描。
*/
@Configuration
// 1. 扫描当前类所在包,及其子包下。
//@ComponentScan
// 2. 扫描指定包下。
//@ComponentScan(basePackages = {"com.qs.springannotation.component_scan.controller"})
// 3. 排除、包含。
@ComponentScan(basePackages = {"com.qs.springannotation.component_scan"},
// 排除(注意:排除优先级高于包含)。
excludeFilters = {
// 根据`注解`排除。
@ComponentScan.Filter(type = FilterType.ANNOTATION, value = {Controller.class}),
// 根据`类型`排除。
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = {UserService.class}),
// 根据`自定义`排除。
@ComponentScan.Filter(type = FilterType.CUSTOM, value = CustomTypeFilter.class),
},
// 包含(注意:`useDefaultFilters=false`表示只扫描包含的)。
useDefaultFilters = false,
includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, value = Repository.class)
})
public class ComponentScanConfig {
public ComponentScanConfig() {
System.out.printf("`%s`无参构造", this.getClass().getName()).println();
}
}
- TypeFilter 接口
/**
* @author wy
* describe `TypeFilter`接口,类型过滤器。
*/
public class CustomTypeFilter implements TypeFilter {
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
// 获取当前类的`资源信息`。
Resource resource = metadataReader.getResource();
// 获取当前类的`Class源信息`。
ClassMetadata classMetadata = metadataReader.getClassMetadata();
// 获取当前类的`注解源信息`。
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
String className = classMetadata.getClassName();
System.out.printf("类的路径:%s", className).println();
return className.contains("dao");
}
}
public enum FilterType {
/**
* 注解
*/
ANNOTATION,
/**
* 类型
*/
ASSIGNABLE_TYPE,
/**
* AspectJ
*/
ASPECTJ,
/**
* 正则
*/
REGEX,
/**
* 自定义
*/
CUSTOM
}
/**
* `@Scope` 范围
* 1. `singleton`:单例(默认,饿汉式加载,容器启动实例就创建好了)。
* 2. `prototype`:多例(懒汉式加载,(IOC容器启动的时候,并不会创建对象,而是在第一次使用的时候才会创建)。
* 3. `request`:同一次请求。
* 4. `session`:同一个会话级别。
*/
@Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Bean("personPrototype")
public Person personPrototype() {
return new Person("personPrototype");
}
/**
* `@Scope` 范围
*/
@Test
public void testScope() {
System.out.println("------------------------------");
// 1. 创建容器(传入`配置类`)。
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext(BeanConfig.class);
System.out.println("------------------------------");
// 2. 容器中获取`Bean`。
Object bean = applicationContext.getBean("personPrototype");
// 3. 打印`Bean`。
System.out.println(bean);
// 2. 容器中获取`Bean`。
Object bean2 = applicationContext.getBean("personPrototype");
// 3. 打印`Bean`。
System.out.println(bean2);
/*
------------------------------
`com.qs.springannotation.beans.Person`有参构造,`name = personPrototype`
Person{name='personPrototype'}
`com.qs.springannotation.beans.Person`有参构造,`name = personPrototype`
Person{name='personPrototype'}
*/
applicationContext.close();
}
/**
* `@Lazy` 懒加载(默认:非懒加载,创建即加载)。
* 主要针对`单例Bean`,容器启动的时候,不创建对象,在第一次使用的时候才会创建该对象。
*/
@Lazy
@Bean(name = "personLazy")
public Person personLazy() {
return new Person("personLazy");
}
/**
* `@Lazy` 懒加载
*/
@Test
public void testLazy() {
System.out.println("------------------------------");
// 1. 创建容器(传入`配置类`)。
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext(BeanConfig.class);
System.out.println("------------------------------");
// 2. 容器中获取`Bean`。
Object bean = applicationContext.getBean("personLazy");
// 3. 打印`Bean`。
System.out.println(bean);
/*
------------------------------
------------------------------
`com.qs.springannotation.beans.Person`有参构造,`name = personLazy`
Person{name='personLazy'}
*/
}
/**
* @author wy
* describe 条件
*/
public class ConditionalConfig {
@Bean
public Qs qs() {
return new Qs(1);
}
/**
* `@Conditional` 指定依赖的条件。
* 当前容器中必须存在`qs组件`,才会创建`qsHome组件`。
*/
@Conditional(QsCondition.class)
@Bean
public QsHome qsHome(Qs qs) {
return new QsHome(qs);
}
}
/**
* @author wy
* describe `Condition`接口,条件。
*/
public class QsCondition implements Condition {
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
// 判断容器中是否存在`qs组件`。
return conditionContext.getBeanFactory().containsBean("qs");
}
}
/**
* `@Conditional` 指定依赖的条件
*/
@Test
public void testConditional() {
System.out.println("------------------------------");
// 1. 创建容器(传入`配置类`)。
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext(ConditionalConfig.class);
System.out.println("------------------------------");
// 2. 容器中获取`Bean`。
Qs qs = applicationContext.getBean(Qs.class);
// 3. 打印`Bean`。
System.out.println(qs);
// 2. 容器中获取`Bean`。
QsHome qsHome = applicationContext.getBean(QsHome.class);
// 3. 打印`Bean`。
System.out.println(qsHome);
/*
------------------------------
`com.qs.springannotation.conditional.Qs`有参构造,`flag = 1`
`com.qs.springannotation.conditional.QsHome`有参构造,`qs = Qs(flag=1)`
------------------------------
Qs(flag=1)
QsHome(qs=Qs(flag=1))
*/
}
/**
* @author wy
* describe `@Import`注解,导入`Bean`。
* 用于导入第三方组件。
*/
@Configuration
// 1. 导入一个`Bean`。
//@Import({com.qs.springannotation.import_bean.Qs.class})
// 2. 导入多个`Bean`。
//@Import({Qs.class, QsHome.class})
// 3. `ImportSelector`接口,自动装配。
//@Import({QsHome.class, MyImportSelector.class})
// 4. `ImportBeanDefinitionRegistrar`接口,注册`Bean定义`。
@Import({QsHome.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
public class ImportConfig {
}
- ImportSelector
/**
* @author wy
* describe `ImportSelector`自动装配
*/
public class MyImportSelector implements ImportSelector {
/**
* 可以获取导入类的注解信息。
*/
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
// 导入组件的id,为全类名路径。
return new String[]{"com.qs.springannotation.import_bean.Qs"};
}
}
- ImportBeanDefinitionRegistrar 注册 Bean 定义。
/**
* @author wy
* describe `ImportBeanDefinitionRegistrar`接口,注册`Bean定义`。
*/
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(QsHome.class);
// 导入组件,可以指定`Bean名称`。
beanDefinitionRegistry.registerBeanDefinition("qsHome2", rootBeanDefinition);
}
}
/**
* @author wy
* describe `@Autowired`注解,自动装配。
*/
@Data
@Service
public class AutowiredService {
private int flag = 0;
/**
* `@Autowired`注解,自动装配。
* 自动装配首先时按照`类型装配`,若在`IOC容器`中发现了多个相同类型的组件,那么就按照`属性名称`来进行装配。
*
* 比如:容器中有二个`AutowiredDao`类型的组件,`autowiredDao`和`autowiredDao1`。
* 1. 通过`@AutoWired`来修饰的`autowiredDao`属性名称时,那么就加载容器的`autowiredDao`组件。
* 2. 若属性名称为`autowiredDao1`时,那么就加载`autowiredDao1`组件。
*/
@Autowired
private AutowiredDao autowiredDao;
@Autowired
private AutowiredDao autowiredDao1;
/**
* 假设容器中即没有`autowiredDao9`,那么在装配的时候就会抛出异常。
* No qualifying bean of type 'com.qs.springannotation.autowired.dao.AutowiredDao' available:
* expected single matching bean but found 3: autowiredDao,autowiredDao1,autowiredDao2
* 若不想抛异常,需要指定`required=false`就可以了。
*/
@Autowired(required = false)
@Qualifier(value = "autowiredDao9")
private AutowiredDao autowiredDao9;
}
/**
* 标注在`配置类上的入参`中(可以不写)。
*/
@Bean
public AutowiredMethodService autowiredMethodService2(@Autowired AutowiredDao autowiredDao) {
AutowiredMethodService service = new AutowiredMethodService();
service.setAutowiredDao(autowiredDao);
return service;
}
@Data
@Primary
@Service
public class AutowiredMethodService {
@Autowired
private AutowiredDao autowiredDao;
public AutowiredMethodService() {
System.out.printf("`%s`无参构造", this.getClass().getName()).println();
}
/**
* 标注在`构造方法`上。
*/
@Autowired
public AutowiredMethodService(AutowiredDao autowiredDao1) {
System.out.printf("`%s`有参构造,`autowiredDao = %s`", this.getClass().getName(), autowiredDao).println();
this.autowiredDao = autowiredDao1;
}
public AutowiredDao getAutowiredDao() {
return autowiredDao;
}
/**
* 标注在`setXX`上。
*/
@Autowired
public void setAutowiredDao(AutowiredDao autowiredDao2) {
System.out.printf("`%s`.setAutowiredDao,`autowiredDao = %s`", this.getClass().getName(), autowiredDao).println();
this.autowiredDao = autowiredDao2;
}
}
/**
* @author wy
* describe `@Qualifier`指定名称装配
*/
@Data
@Service
public class QualifierService {
private int flag = 1;
/**
* `@Qualifier`注解,指定名称装配。
*
* `@AutoWired`默认使用`BY_NAME`。
* 当发现多个`同类型的Bean`,就通过`BY_NAME`。
* 需要通过名称装配,使用`@Qualifier`指定名称装配。
*/
@Qualifier(value = "autowiredDao1")
@Autowired
private AutowiredDao autowiredDao;
@Qualifier(value = "autowiredDao")
@Autowired
private AutowiredDao autowiredDao1;
}
/**
*`@Primary`注解,按类型(`BY_TYPE`)装配时优先。
*/
@Primary
@Bean
public AutowiredDao autowiredDao2() {
AutowiredDao dao = new AutowiredDao();
dao.setFlag(2);
return dao;
}
/**
* 默认通过类型(`BY_TYPE`),当发现多个`同类型的Bean`,就通过名称(`BY_NAME`)。
*/
@Primary
@Bean(autowire = Autowire.BY_TYPE)
// @Bean(autowire = Autowire.BY_NAME)
public AutowiredService autowiredService3() {
AutowiredService service = new AutowiredService();
service.setFlag(3);
return service;
}
/**
* @author wy
* describe `@Primary`注解,按类型(`BY_TYPE`)装配时优先。
*/
@Data
@Service
public class PrimaryService {
private int flag = 2;
/**
* `@Autowired`失败问题。
* 1. `Service`使用类型(`BY_TYPE`)注入时,`Dao`会注入`@Primary`修饰的。
* 2. `Service`使用名称(`BY_NAME`)注入时,`Dao`只能使用名称注入。
*/
@Autowired
private AutowiredDao autowiredDao;
@Qualifier(value = "autowiredDao1")
@Autowired
private AutowiredDao autowiredDao1;
@Autowired
private AutowiredDao autowiredDao2;
}
/**
* @author wy
* describe `@Resource`注解,`JSR250`规范。
* 和`@AutoWired`的功能差不多一样,但是不支持`@Primary`和`@Qualifier`。
*/
@Data
@Service
public class ResourceService {
@Resource
private AutowiredDao resourceDao;
}
/**
* @author wy
* describe `@InJect`注解,`JSR330`规范。
* 需要导入`jar`包`javax.inject`。
* 和`@AutoWired`的功能差不多一样,支持`@Primary`和`@Qualifier`,但是没有`require=false`的功能。
*/
@Service
@Data
public class InjectService {
@Inject
private AutowiredDao injectDao;
}
/**
* @author wy
* describe `@Profile`注解,环境注入,根据环境来激活标识不同的Bean。
* 1. `@Profile`标识在类上,那么只有当前环境匹配,整个配置类才会生效。
* 2. `@Profile`标识在`Bean`上 ,那么只有当前环境的Bean才会被激活。
* 3. 没有标志为`@Profile`的`Bean`,不管在什么环境都可以被激活。
*
* `EmbeddedValueResolverAware`接口,内嵌式值解析器。
*/
@Configuration
@PropertySource(value = {"classpath:ds.properties"})
public class ProfileConfig implements EmbeddedValueResolverAware {
private String classDriver;
private String jdbcUrl;
@Value("${ds.username}")
private String userName;
@Value("${ds.password}")
private String password;
@Override
public void setEmbeddedValueResolver(StringValueResolver stringValueResolver) {
this.jdbcUrl = stringValueResolver.resolveStringValue("${ds.jdbcUrl}");
this.classDriver = stringValueResolver.resolveStringValue("${ds.classDriver}");
}
/**
* 标识为测试环境,才会被装配。
*/
@Bean
@Profile(value = "test")
public DataSource testDS() {
return buildDataSource(new DruidDataSource());
}
/**
* 标识开发环境,才会被激活。
*/
@Bean
@Profile(value = "dev")
public DataSource devDS() {
return buildDataSource(new DruidDataSource());
}
/**
* 标识生产环境,才会被激活。
*/
@Bean
@Profile(value = "prod")
public DataSource prodDS() {
return buildDataSource(new DruidDataSource());
}
private DataSource buildDataSource(DruidDataSource dataSource) {
dataSource.setDriverClassName(classDriver);
dataSource.setUrl(jdbcUrl);
dataSource.setUsername(userName);
dataSource.setPassword(password);
return dataSource;
}
}
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext();
// 设置环境属性(或者JVM参数`-Dspring.profiles.active=test,dev,prod`)
applicationContext
.getEnvironment()
.setActiveProfiles("test", "dev");
- @PropertySource 导入属性配置文件
/**
* @author wy
* describe `@PropertySource`导入属性配置文件。
*/
@Configuration
@PropertySource(value = {"classpath:person.properties"})
public class ValueConfig {
@Bean
public Person person() {
return new Person();
}
}
- @Value 注入属性
/**
* @author wy
* describe `@Value`注解,注入属性
*/
@Data
public class Person {
@Value("骑士")
private String firstName;
/**
* `SPEL`表达式。
*/
@Value("#{28-8}")
private Integer age;
/**
* 读取外部配置文件的值
*/
@Value("${person.lastName}")
private String lastName;
}