Spring五、注解编程基础组件
Spring5开启了零配置编程时代,脱离xml完全使用注解编程,为Spring Boot奠定了开发基础。
案例demo地址
一、配置组件
1. @Configuration
声明一个类为Spring IOC容器,如果这个类方法头上注册了@Bean,就会作为Spring容器中的Bean。等价于xml配置文件。
@Configuration
public class MyConfig {
/**
* 1. 默认类名首字母小写
* 2. 其次就是取方法名
* 3. 最后优先取Bean的value
* @return
*/
@Bean(value = "myPerson")
public Person getPerson() {
System.out.println("create person by myself");
return new Person("shen", "18");
}
}
普通xml方式配置的IOC容器获取方法:
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");
Person person = (Person) applicationContext.getBean("myPerson");
注解@Configuration方式配置的IOC容器获取方法:
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
Person person = (Person) applicationContext.getBean("person");
2. @ComponentScan、@ComponentScans
在配置类上添加@ComponentScan注解,相当于之前的context:component-scan
@Configuration
//1. 简单使用ComponentScan注解扫描,扫描包下的bean使用@Service、@Controller、@Component等注解配合,可以扫描到
//@ComponentScan(value = "com.bigshen.demo.project")
//2. useDefaultFilters = false, 不使用Spring默认的扫描filter,
// 自己指定扫描规则
@ComponentScan(
value = "com.bigshen.demo.project",
useDefaultFilters = false, // 使用自定义的扫描过滤规则
includeFilters = {
// @ComponentScan.Filter(type = FilterType.ANNOTATION, value = Controller.class), // 使用注解扫描
// @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = MyDao.class), // 直接指定类型扫描
@ComponentScan.Filter(type = FilterType.CUSTOM, value = MatchedFilter .class)}, // 直接自定义类型扫描
excludeFilters = {
@ComponentScan.Filter(type = FilterType.CUSTOM, value = UnMatchedFilter.class) // 直接自定义类型排除
}
)
public class MyConfig {
}
public class MatchedFilter implements TypeFilter {
/**
*
* @param metadataReader 类的信息
* @param metadataReaderFactory spring上下文
* @return
* @throws IOException
*/
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
// 当前类注解的信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
// 当前类的信息
ClassMetadata classMetadata = metadataReader.getClassMetadata();
// 当前资源信息
Resource resource = metadataReader.getResource();
String clazzName = classMetadata.getClassName();
System.out.println("--------- " + clazzName);
if (clazzName.contains("er")){
return true;
}
return false;
}
}
public class UnMatchedFilter implements TypeFilter {
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
ClassMetadata classMetadata = metadataReader.getClassMetadata();
String className = classMetadata.getClassName();
if (className.contains("Controller")) {
// 不匹配
return true;
}
return false;
}
}
3. @Scope
指定类的作用域,singleton、prototype、request、session
4. @Lazy
Spring中Bean默认是非懒加载的,即在容器初始化时就将实例初始化,使用@Lazy注解指定该Bean为懒加载。
5. @Conditional
Spring4开始提供,按照一定的条件进行判断,满足条件给容器注册Bean。 自定义的条件实现'org.springframework.context.annotation.Condition'
public class WindowCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
Environment environment = context.getEnvironment();
String system = environment.getProperty("os.name");
System.out.println("System -- " + system);
if (system.contains("Window")) {
return true;
}
return false;
}
}
@Configuration
public class MyConfig {
@Conditional(WindowCondition.class)
@Bean
public Person shen() {
System.out.println("将shen添加到ioc容器中");
return new Person("Shen", "18");
}
@Bean
@Conditional(LinuxCondition.class)
public Person liu() {
System.out.println("将liu添加到ioc容器中");
return new Person("liu", "18");
}
@Bean
@Conditional(WindowCondition.class)
public Person wang() {
System.out.println("将wang添加到ioc容器中");
return new Person("wang", "18");
}
}
6. @Import
导入外部资源
@Import源码,可以指定 org.springframework.context.annotation.ImportSelector 或者 org.springframework.context.annotation.ImportBeanDefinitionRegistrar 的实现类来作为导入规则,也可以是普通的类
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {
/**
* {@link Configuration}, {@link ImportSelector}, {@link ImportBeanDefinitionRegistrar}
* or regular component classes to import.
*/
Class<?>[] value();
}
@Configuration
@Import(value = {Cat.class, MyImport.class, MyRegistry.class})
public class MyConfig {
/**
*
* 注册Bean的几种方式
* 1. @Bean 导入单个Bean
* 2. @ComponentScan (默认扫描 @Controller、@Service、@Repository、@Component)
* 3. @Import 快速导入Bean
* a. @Import 直接参数导入
* b. 实现 ImportSelector 自定义规则实现
* c. 实现 ImportBeanDefinitionRegistrar 直接往IOC容器中注册
* 4. FactoryBean , 把需要注册的对象封装为FactoryBean
* a. FactoryBean 负责将Bean注册到Ioc的Bean
* b. BeanFactory Ioc容器,从中获得Bean对象
* @return
*/
@Bean
public Person person() {
return new Person("shen", "19");
}
@Bean
public FactoryBean world() {
return new MyFactoryBean();
}
}
public class MyImport implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
// 直接返回 class集合,放入IOC容器
return new String[]{"com.bigshen.demo.project.entity.Apple", "com.bigshen.demo.project.entity.Orange"};
}
}
public class MyRegistry implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// 包里同时声明了Apple 和 Orange ,才把Fruit放入IOC容器
Boolean containsApple = registry.containsBeanDefinition("com.bigshen.demo.project.entity.Apple");
Boolean containsOrange = registry.containsBeanDefinition("com.bigshen.demo.project.entity.Orange");
if (containsApple && containsOrange) {
BeanDefinition beanDefinition = new RootBeanDefinition(Apple.class);
registry.registerBeanDefinition("apple", beanDefinition);
}
}
}
public class MyFactoryBean implements FactoryBean<World> {
@Override
public World getObject() throws Exception {
return new World();
}
@Override
public Class<?> getObjectType() {
return World.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
7.生命周期控制 @PostConstruct、@PreDestroy、@DependsOn
@PostConstruct 用在方法上,用于指定Bean的初始化方法
@PreDestroy 用在方法上,用于指定销毁方法
@DependsOn 定义Bean初始化及销毁时的顺序
/**
* bean的生命周期 : 创建(实例化-初始化)、使用、销毁
* 3中方式都可实现 对生命周期进行控制:
* a、@PostConstruct、@PreDestroy
* b、@Bean本身的 initMethod()、destroyMethod()
* c、接口 InitializingBean#afterPropertiesSet()、DisposableBean#destroy()
* @return
*/
Bean的完整生命周期经历了各种方法调用,这些方法可以划分为以下几类:
1、Bean自身的方法 : 这个包括了Bean本身调用的方法和通过配置文件中<bean>的init-method和destroy-method指定的方法
2、Bean级生命周期接口方法 : 这个包括了BeanNameAware、BeanFactoryAware、InitializingBean和DiposableBean这些接口的方法
3、容器级生命周期接口方法 : 这个包括了InstantiationAwareBeanPostProcessor 和 BeanPostProcessor 这两个接口实现,一般称它们的实现类为“后处理器”。
4、工厂后处理器接口方法 : 这个包括了AspectJWeavingEnabler, ConfigurationClassPostProcessor, CustomAutowireConfigurer等等非常有用的工厂后处理器 接口的方法。工厂后处理器也是容器级的。在应用上下文装配配置文件之后立即调用。
二、赋值组件、自动装配
1. @Componment
泛指组件,当组件不好归类时使用
2. @Service、@Controller、@Repository
@Service 用于标注业务层组件
@Controller 用于标注控制层组件
@Repository 用于标注数据访问层、即Dao层组件
3. @Value
普通数据类型赋值 可结合Spring EL表达式从配置文件取值
@Value("${child.family}")
private String family;
4. @Autowired
默认按照类型装配,如果想按名称进行装配,可配合@Qualifier使用
5. @Resource
按照名称装配,如果找不到名称匹配的Bean则会按照类型装配
6 @PropertySource
读取配置文件
@Configuration
@PropertySource("classpath:values.properties")
public class MyConfig {
@Bean
public Child child() {
return new Child();
}
}
7. @Qualifier
如存在多个实例,配合@Autowired使用,指定根据名称装配
@Autowired
@Qualifier("childService")
public HumanService humanService;
8. @Primary
自动装配时如果匹配到多个Bean,使用@Primary作为首选者,否则抛出异常
如一个接口有多个实现类,这些实现类中有一个使用了@Primary注解,则在@Autowired注入时会优先使用这个实现类
三、织入组件
1. ApplicationContextAware
可以通过这个上下文环境对象得到Spring容器中的Bean
2. BeanDefinitionRegistryPostProcessor
BeanDefinitionRegistryPostProcessor实现了BeanFactoryPostProcessor接口,是Spring框架的BeanDefinitionRegistry的后处理器,用来注册额外的BeanDefinition
四、切面组件
1. @EnableTransactionManagement
启用对事物管理的支持
2. @Transactional
配置声明式事物信息