在开发的过程中,大多数程序员都在使用Spring Boot开发,这样将配置工作量减少了很多,本文就是介绍一下使用注解开发,
Spring 的版本为5.2.6.RELEASE。
添加依赖
UTF-8
UTF-8
1.8
5.2.6.RELEASE
4.13
org.springframework
spring-context
${spring.version}
junit
junit
${junit.version}
test
Configuration & @Bean
@Configuration这个注解是将这个类当作一个配置类,类似Spring的配置文件;
@Bean是往容器中注册一个Bean。
创建一个Person
package com.edu.spring.bean;
// 可以在idea中添加lombok组件,省略了get/set、toString方法
public class Person {
private String name;
private Integer age;
}
配置类
package com.edu.spring.config;
import com.edu.spring.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MainConfig {
@Bean
public Person person(){
Person person = new Person("xiaoyao",20);
return person;
}
}
编写测试类
package com.edu.spring;
import com.edu.spring.bean.Person;
import com.edu.spring.config.MainConfig;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class MainTest {
// 可以正常输出person这个类的属性值,表示注册成功。
@Test
public void annotationConfig(){
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
Person person = context.getBean(Person.class);
System.out.println(person.getName()+" "+ person.getAge());
}
}
CompnonentScan
@ComponentScan这个注解是在配置文件中需要制定要扫描的包。
@CompnonentScan参数介绍:
- value制定要扫描的包
- excludeFilters 指定扫描的时候按照规则排除哪些组件
- includeFilters 制定扫描的时候只需要哪些组件
- ComponentScans 可以设置多个ComponentScan。
package com.edu.spring.config;
import com.edu.spring.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
/**
* 配置类
* Componentscan
* value制定要扫描的包
* excludeFilters 指定扫描的时候按照规则排除哪些组件
* includeFilters 制定扫描的时候只需要哪些组件
* ComponentScans 可以设置多个ComponentScan。
*/
@Configuration
@ComponentScan(value = "com.edu.spring")
public class MainConfig {
@Bean
public Person person(){
Person person = new Person("xiaoyao",20);
return person;
}
}
创建其他类
package com.edu.spring.controller;
import org.springframework.stereotype.Controller;
@Controller
public class BookController {
}
package com.edu.spring.dao;
import org.springframework.stereotype.Repository;
@Repository
public class BookDao {
}
package com.edu.spring.service;
import org.springframework.stereotype.Service;
@Service
public class BookService {
}
使用测试方法componentScan,输出结果为:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig
bookController
bookDao
bookService
person
如果添加了excludeFilters = {@Filter(type = FilterType.ANNOTATION,classes = {Controller.class})},就会输出如下所示,
就是在扫描的时候,将使用@Controller的类排除在外
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig
bookDao
bookService
person
FilterType
- ANNOTATION:按照指定注解进行过滤
- ASSIGNABLE_TYPE: 按照给定的类型进行过滤
- ASPECTJ: 使用aspectj表达式进行过滤
- REGEX: 使用正则表达式进行过滤
- CUSTOM: 使用自定义规则进行过滤。
自定义Filter
package com.edu.spring.service;
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;
public class CustomFilter implements TypeFilter {
/**
* 如果符合要求就过滤,如果不符合要求不过滤。
* @param metadataReader 读取到当前正在扫描的类信息
* @param metadataReaderFactory 获取其他类信息
* @return
* @throws IOException
*/
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);
return false;
}
}
测试
需要修改配置类:
@ComponentScan(value = "com.edu.spring",excludeFilters = {
//@Filter(type = FilterType.ANNOTATION,classes = {Controller.class})
@Filter(type = FilterType.CUSTOM,classes = {CustomFilter.class})
})
输出结果为:
--->com.edu.spring.MainTest
--->com.edu.spring.bean.Person
--->com.edu.spring.controller.BookController
--->com.edu.spring.dao.BookDao
--->com.edu.spring.service.BookService
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig
bookController
bookDao
bookService
person
@Scope
@Scope 用来定义类的类型,是单实例形式还是多实例的形式。
- SCOPE_PROTOTYPE 每次使用的时候,都会创建一个新的对象
- SCOPE_SINGLETON 容器内单例,默认值
- SCOPE_REQUEST 每次发送请求都会创建
- SCOPE_SESSION 每次请求都会创建一个session
编写新的配置类
package com.edu.spring.config;
import com.edu.spring.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
@Configuration
public class MainConfig2 {
@Bean
@Scope
//@Scope(value = "prototype")
public Person person(){
Person person = new Person("xiaoyao",20);
return person;
}
}
测试方法
@Test
public void scope(){
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig2.class);
Person bean = context.getBean(Person.class);
Person bean1 = context.getBean(Person.class);
System.out.println(bean == bean1);
}
@Conditional
@Conditional 按照条件进行注册Bean。
自定义Condition
package com.edu.spring.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.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class WindowCondition implements Condition {
/**
* 根据条件进行比较
* @param context 判断条件使用的上下文
* @param metadata 注释信息
* @return
*/
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
//可以获取 beanfactory
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
//获取类加载信息
ClassLoader classLoader = context.getClassLoader();
// 获取环境变量
Environment environment = context.getEnvironment();
//获取bean定义的注册类
BeanDefinitionRegistry registry = context.getRegistry();
String property = environment.getProperty("os.name");
if (property.contains("Windows")){
return true;
}
return false;
}
}
package com.edu.spring.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.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class MacCondition implements Condition {
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
//可以获取 beanfactory
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
//获取类加载信息
ClassLoader classLoader = context.getClassLoader();
// 获取环境变量
Environment environment = context.getEnvironment();
//获取bean定义的注册类
BeanDefinitionRegistry registry = context.getRegistry();
String property = environment.getProperty("os.name");
if (property.contains("Mac")){
return true;
}
return false;
}
}
配置文件
package com.edu.spring.config;
import com.edu.spring.bean.Person;
import com.edu.spring.condition.MacCondition;
import com.edu.spring.condition.WindowCondition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
@Configuration
public class MainConfig2 {
@Bean
@Scope(value = "prototype")
public Person person() {
Person person = new Person("xiaoyao",20);
return person;
}
@Conditional( {WindowCondition.class})
@Bean("bill")
public Person person1() {
return new Person("Bill Gates", 65);
}
@Conditional({MacCondition.class})
@Bean("linus")
public Person person2() {
return new Person("linus", 48);
}
}
@Import
给容器中注册组件:
1.包扫描 + 组件标注组件(@Controller/@Service/@Repository/@Component)
2.@Bean 导入第三方包里面的组件
3.@Import 快速给容器中导入一个组件 id为全类名
@ImportSelector:返回需要导入的组件的全类名数组;
@ImportBeanDefinitionRegistrar: 手动注册bean到容器中
4.使用Spring提供的FactoryBean
默认获取具体的bean
如果想要获取工厂bean本身,需要添加&。
Import
package com.edu.spring.config;
import com.edu.spring.bean.*;
import com.edu.spring.condition.MacCondition;
import com.edu.spring.condition.WindowCondition;
import com.edu.spring.registrar.CustomBeanDefinitionRegistrar;
import com.edu.spring.selector.CustomImportSelector;
import org.springframework.context.annotation.*;
/**
* @author xiaoyao.
* @date 2020/4/29.
* @time 4:46 PM.
*/
@Configuration
@Import({Color.class})
public class MainConfig2 {
@Bean
@Scope(value = "prototype")
public Person person() {
Person person = new Person("xiaoyao",20);
return person;
}
@Conditional( {WindowCondition.class})
@Bean("bill")
public Person person1() {
return new Person("Bill Gates", 65);
}
@Conditional({MacCondition.class})
@Bean("linus")
public Person person2() {
return new Person("linus", 48);
}
}
测试方法:
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig2.class);
String[] definitionNames = context.getBeanDefinitionNames();
for (String name:definitionNames){
System.out.println(name);
}
输出结果为:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig2
com.edu.spring.bean.Color
person
linus
ImportSelector
需要实现自定义的ImportSelector
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
import java.util.Set;
/**
* 自定义逻辑返回需要导入的组件
*/
public class CustomImportSelector implements ImportSelector {
/**
* 返回值,就是导入到容器中的组件全类名
* @param importingClassMetadata 当前标注@Import注解的类的所有注解信息
* @return
*/
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"com.edu.spring.bean.Red"};
}
}
配置文件为:
package com.edu.spring.config;
import com.edu.spring.bean.*;
import com.edu.spring.condition.MacCondition;
import com.edu.spring.condition.WindowCondition;
import com.edu.spring.registrar.CustomBeanDefinitionRegistrar;
import com.edu.spring.selector.CustomImportSelector;
import org.springframework.context.annotation.*;
/**
* @author xiaoyao.
* @date 2020/4/29.
* @time 4:46 PM.
*/
@Configuration
@Import({Color.class, CustomImportSelector.class})
public class MainConfig2 {
@Bean
@Scope(value = "prototype")
public Person person() {
Person person = new Person("xiaoyao",20);
return person;
}
@Conditional( {WindowCondition.class})
@Bean("bill")
public Person person1() {
return new Person("Bill Gates", 65);
}
@Conditional({MacCondition.class})
@Bean("linus")
public Person person2() {
return new Person("linus", 48);
}
}
结果为:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig2
com.edu.spring.bean.Color
com.edu.spring.bean.Red
person
linus
ImportBeanDefinitionRegistrar
实现自定义的ImportBeanDefinitionRegistrar。
package com.edu.spring.registrar;
import com.edu.spring.bean.Blue;
import com.edu.spring.bean.RainBow;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
public class CustomBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
/**
* 手动注册bean
* @param importingClassMetadata 当前类的注解信息
* @param registry bean定义饿的注册类
* @param importBeanNameGenerator 产生bean的名字
*/
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
boolean blue = registry.containsBeanDefinition("com.edu.spring.bean.Blue");
boolean red = registry.containsBeanDefinition("com.edu.spring.bean.Red");
if (red && blue){
RootBeanDefinition rootBeanDefinition = new RootBeanDefinition();
rootBeanDefinition.setBeanClass(RainBow.class);
registry.registerBeanDefinition("rainbow",rootBeanDefinition);
}
}
}
配置文件:
package com.edu.spring.config;
import com.edu.spring.bean.*;
import com.edu.spring.condition.MacCondition;
import com.edu.spring.condition.WindowCondition;
import com.edu.spring.registrar.CustomBeanDefinitionRegistrar;
import com.edu.spring.selector.CustomImportSelector;
import org.springframework.context.annotation.*;
/**
* @author xiaoyao.
* @date 2020/4/29.
* @time 4:46 PM.
*/
@Configuration
@Import({Color.class, CustomImportSelector.class,CustomBeanDefinitionRegistrar.class})
public class MainConfig2 {
@Bean
@Scope(value = "prototype")
public Person person() {
Person person = new Person("xiaoyao",20);
return person;
}
@Conditional( {WindowCondition.class})
@Bean("bill")
public Person person1() {
return new Person("Bill Gates", 65);
}
@Conditional({MacCondition.class})
@Bean("linus")
public Person person2() {
return new Person("linus", 48);
}
}
输出结果为:
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
mainConfig2
com.edu.spring.bean.Color
com.edu.spring.bean.Red
com.edu.spring.bean.Blue
person
linus
rainbow
FactoryBean
添加创建bean的工厂:
package com.edu.spring.bean;
import org.springframework.beans.factory.FactoryBean;
public class ColorFactoryBean implements FactoryBean {
public Color getObject() throws Exception {
return new Color();
}
public Class> getObjectType() {
return Color.class;
}
}
通过colorFactoryBean获取到的对象是Color,如果想要获取ColorFactoryBean,需要在名字之前添加&, 这样在获取的时候,Spring才会判断出想要的是
工厂类,而不是具体的类。