SpringIOC容器的注解使用
一、@ComponentScan 进行包扫描
在配置类上写 @CompentScan 注解来进行包扫描
@Configuration
@ComponentScan(basePackages = {"com.yufeng.testcompentscan"})
public class MainConfig {
}
1、排除用法; excludeFilters( 排除标注@Controller注解 和 TestService类)
@Configuration
@ComponentScan(basePackages = {"com.yufeng.testcompentscan"}, excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION,value = {Controller.class}),
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,value = {TestService.class})
})
public class MainConfig {
}
2、包含用法 includeFilters; 注意,若使用包含的用法,需要把useDefaultFilters属性设置为false(true表示扫描全部的 @Controller @Service @Component @Repository 标注的类) ;
@ComponentScan.Filter type的类型:
- FilterType.ANNOTATION:注解形式的,@Controller @Service @Repository @Compent;
- FilterType.ASSIGNABLE_TYPE:指定类型的,@ComponentScan.Filter(type =FilterType.ASSIGNABLE_TYPE,value = {Test.class});
- FilterType.ASPECTJ:aspectj类型的(不常用);
- FilterType.REGEX:正则表达式的 (不常用);
- FilterType.CUSTOM:自定义的,实现 TypeFilter 接口;
FilterTyp.CUSTOM 的使用:
public class CustomFilterType implements TypeFilter {
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
//获取当前类的注解源信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
//获取当前类的class的源信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();
//获取当前类的资源信息
Resource resource = metadataReader.getResource();
System.out.println("类的路径:"+classMetadata.getClassName());
if(classMetadata.getClassName().contains("dao")) {
return true;
}
return false;
}
}
@ComponentScan(basePackages = {"com.yufeg.testcompentscan"}, includeFilters = {
@ComponentScan.Filter(type = FilterType.CUSTOM,value = CustomFilterType.class)
},useDefaultFilters = false)
二、向IOC容器中添加组件的4种方式
1、@CompentScan + @Controller @Service @Respository @Compent;
2、@Bean 的方式导入组件(适用于导入第三方类的组件);
@Configuration
@Import(value = {Person.class, Car.class})
public class MainConfig {
}
(2)通过 @Import 导入实现 ImportSeletor 接口的类 (导入组件的id为全类名路径)
@Configuration
@Import(value = {Person.class, Car.class, MyImportSelector.class})
public class MainConfig {
}
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"com.yufeng.testimport.compent.Dog"};
}
}
(3)通过@Import 导入 ImportBeanDefinitionRegistrar 导入组件 (可以指定bean的名称)
@Configuration
@Import(value = {Person.class, Car.class, MyImportSelector.class, MyBeanDefinitionRegister.class})
public class MainConfig {
}
public class MyBeanDefinitionRegister implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Cat.class);
registry.registerBeanDefinition("cat",rootBeanDefinition);
}
}
4、通过实现 FactoryBean 接口来实现注册组件;
public class CarFactoryBean implements FactoryBean<Car> {
@Override
public Car getObject() throws Exception {
return new Car();
}
@Override
public Class<?> getObjectType() {
return Car.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
@Configuration
public class MainConfig {
@Bean
public CarFactoryBean carFactoryBean() {
return new CarFactoryBean();
}
}
public class MainClass {
public static void main(String[] args) throws Exception {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MainConfig.class);
// 获取到 car 对象
Object bean = ctx.getBean("carFactoryBean");
System.out.println(bean);
// 获取到 carFactoryBean 对象
Object bean2 = ctx.getBean("&carFactoryBean");
System.out.println(bean2);
}
}
三、Bean的作用域
1、在不指定@Scope的情况下,所有的bean都是单实例的bean,而且是饿汉加载(容器启动实例就创建好了);
- singleton 单实例的(默认);
- prototype 多实例的;
- request 同一次请求;
- session 同一个会话级别;
四、@Conditional进行条件判断等
1、实现 Condition 接口;
public class TulingCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
//判断容器中是否有myAspect的组件
if(context.getBeanFactory().containsBean("myAspect")) {
return true;
}
return false;
}
}
public class MainConfig {
//@Bean
public MyAspect myAspect() {
return new MyAspect();
}
@Bean
@Conditional(value = MyCondition.class)
public Car car() {
return new Car();
}
}
五、Bean的初始化方法和销毁方法
由容器管理Bean的生命周期,我们可以通过自己指定bean的初始化方法和bean的销毁方法 。
@Configuration
public class MyConfig {
@Bean(initMethod = "init", destroyMethod = "destroy")
public Car car() {
return new Car();
}
}
public class Car {
public Car() {
System.out.println("Car的构造方法..........");
}
// 初始化方法
public void init() {
System.out.println("Car的初始化方法......init");
}
// 销毁方法
public void destroy() {
System.out.println("Car的销毁方法.....destroy");
}
}
单实例bean的话,容器启动的时候,bean的对象就创建了,而且容器销毁的时候,也会调用Bean的销毁方法。
多实例bean的话,容器启动的时候,bean是不会被创建的而是在获取bean的时候被创建,而且bean的销毁不受IOC容器的管理。
@Configuration
@ComponentScan(basePackages = {"com.yufeng.testbeanlifecycle.my"})
public class MyConfig {
}
@Component
public class Book {
public Book() {
System.out.println("book 的构造方法");
}
@PostConstruct
public void init() {
System.out.println("book 的PostConstruct标志的方法");
}
@PreDestroy
public void destory() {
System.out.println("book 的PreDestory标注的方法");
}
}
3、通过实现 InitializingBean 和 DisposableBean 这两个接口的bean的初始化以及销毁方法;
@Configuration
@ComponentScan(basePackages = {"com.yufeng.testbeanlifecycle.my"})
public class MyConfig {
}
@Component
public class Dog implements InitializingBean, DisposableBean {
public Dog() {
System.out.println("-- Dog 构造方法");
}
// 在Bean初始化的时候执行,可以操作Bean的属性
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("-- Dog 的 afterPropertiesSet");
}
@Override
public void destroy() throws Exception {
System.out.println("-- Dog 的 destroy");
}
}
4、通过 Spring的 BeanPostProcessor (bean的后置处理器 )会拦截所有bean创建过程;(可以用来操作bean的属性)
postProcessBeforeInitialization 在init方法之前调用; postProcessAfterInitialization 在init方法之后调用;@Configuration
@ComponentScan(basePackages = {"com.yufeng.testbeanlifecycle.my"})
public class MyConfig {
}
@Component public class MyBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("MyBeanPostProcessor...postProcessBeforeInitialization:"+beanName); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("MyBeanPostProcessor...postProcessAfterInitialization:"+beanName); return bean; } }
@Component
public class Dog implements InitializingBean, DisposableBean {
public Dog() {
System.out.println("-- Dog 构造方法");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("-- Dog 的 afterPropertiesSet");
}
@Override
public void destroy() throws Exception {
System.out.println("-- Dog 的 destroy");
}
}
启动后结果如下:

六、自动装配
1、@Autowired
配置类:
@Configuration
@ComponentScan(basePackages = {"com.yufeng.testautowired.autowired.my"})
public class MainConfig {
@Bean
public Car car() {
return new Car();
}
@Bean
public Car car2() {
return new Car("car2-----noise");
}
}
实体类:
public class Car {
private String noise;
public Car() {}
public Car(String noise) {
this.noise = noise;
}
// getter、 setter、toString方法
}
Service类:
@Service
public class MyService {
@Autowired
private Car car2;
public void aa() {
System.out.println("--- test: " + car2);
}
}
启动类:
public class MainDemo {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MainConfig.class);
MyService myService = (MyService) ctx.getBean("myService");
myService.aa();
}
}
运行结果:--- test: Car{noise='car2-----noise'}
结论:
(1)@Autowired 首先时按照类型进行装配,若在IOC容器中发现了多个相同类型的组件,那么就按照 属性名称来进行装配。
(2)如果我们需要指定特定的组件来进行装配,我们可以通过使用 @Qualifier("car") 来指定装配的组件,或者在配置类上的 @Bean 加上 @Primary注解;
注意:@Qualifier 优先级高于 @Primary;
(3)@Autowired 可以标注在方法上、构造方法上、配置类的方法入参上;
a. @Qualifier 使用
@Service
public class MyService {
@Autowired
@Qualifier("car")
private Car car2;
public void aa() {
System.out.println("--- test: " + car2);
}
}
运行结果:--- test: Car{noise='null'}
b. @Primary
@Configuration
@ComponentScan(basePackages = {"com.tuling.testautowired.autowired.my"})
public class MainConfig {
@Bean
public Car car() {
return new Car();
}
@Bean
@Primary
public Car car2() {
return new Car("car2-----noise");
}
}
2、@Resource (JSR250规范)
@Resource的作用相当于@Autowired,只不过@Autowired按照 byType自动注入,@Resource默认按照 byName 进行装配。
@Resource装配顺序:
- ①如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常。
- ②如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常。
- ③如果指定了type,则从上下文中找到类似匹配的唯一bean进行装配,找不到或是找到多个,都会抛出异常。
- ④如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配。
3、@InJect(JSR330规范),需要导入jar包依赖;
功能和支持@Primary功能 ,但是没有Require=false的功能;
@Inject 没有 required 属性,因此在找不到合适的依赖对象时 inject 会失败,而 @Autowired 可以使用 required=false 来允许 null 注入。
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
七、通过@Value +@PropertySource来给组件赋值
配置类:
@Configuration
@PropertySource(value = {"classpath:my.properties"})
public class MainConfig {
@Bean
public Person person() {
return new Person();
}
}
配置文件 my.properties:
person.lastName=吹雪
实体类:
public class Person {
@Value("西门")
private String firstName;
@Value("#{28-2}")
private Integer age;
@Value("${person.lastName}")
private String lastName;
// getter 和 setter 的方法
}
运行结果:Person{firstName='西门', age=26, lastName='吹雪'}
八、自定义组件需要使用Spring IOC中的Bean,可以通过实现 XXXAware 接口来实现
实现 ApplicationContextAware 和 BeanNameAware 接口:
@Component
public class CustomCompent implements ApplicationContextAware,BeanNameAware {
private ApplicationContext applicationContext;
@Override
public void setBeanName(String name) {
System.out.println("current bean name is :【"+name+"】");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
九、通过@Profile注解 来根据环境来激活标识不同的Bean
@Profile标识在类上,那么只有当前环境匹配,整个配置类才会生效;
@Profile标识在Bean上 ,那么只有当前环境的Bean才会被激活没有标志为@Profile的 bean 不管在什么环境都可以被激活;
配置类:
@Configuration
@PropertySource(value = {"classpath:ds.properties"})
public class MainConfig implements EmbeddedValueResolverAware {
@Value("${ds.username}")
private String userName;
@Value("${ds.password}")
private String password;
private String jdbcUrl;
private String classDriver;
@Override
public void setEmbeddedValueResolver(StringValueResolver resolver) {
this.jdbcUrl = resolver.resolveStringValue("${ds.jdbcUrl}");
this.classDriver = resolver.resolveStringValue("${ds.classDriver}");
}
@Bean
@Profile(value = "test")
public DataSource testDs() {
return buliderDataSource(new DruidDataSource());
}
@Bean
@Profile(value = "dev")
public DataSource devDs() {
return buliderDataSource(new DruidDataSource());
}
@Bean
@Profile(value = "prod")
public DataSource prodDs() {
return buliderDataSource(new DruidDataSource());
}
private DataSource buliderDataSource(DruidDataSource dataSource) {
dataSource.setUsername(userName);
dataSource.setPassword(password);
dataSource.setDriverClassName(classDriver);
dataSource.setUrl(jdbcUrl);
return dataSource;
}
}
配置文件 ds.properties :
ds.username=root ds.password=123456 ds.jdbcUrl=jdbc:mysql://localhost:3306/test ds.classDriver=com.mysql.jdbc.Driver
启动类:
public class MainClass {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.getEnvironment().setActiveProfiles("test","dev");
ctx.register(MainConfig.class);
ctx.refresh();
for(String beanName: ctx.getBeanDefinitionNames()) {
System.out.println("容器中的BeanName:"+beanName);
}
}
}
结果:


浙公网安备 33010602011771号