Spring注解整理

1.@Configuration

使用这个注解来告诉Spring这是一个配置类,来替代原来的


    
    

2.@Bean

使用这个注解将一个对象实例注册进IOC容器中作为一个bean,默认的bean id为访问名,也可以显示指定id以及init、destroy方法,如@Bean(name = "sunwukong",initMethod = "init",destroyMethod = "destroy")
除了可以在注解中指定init、destroy方法外,还可以通过实现InitializingBean与DisposableBean来实现bean的初始化与销毁逻辑。

3.@ComponentScan

在原来的Spring xml配置文件中需要配置


来表示将这个包下的带有@Controller、@Service、@Repository、@Component的类都注册到IOC容器里面。
现在可以在@Configuration标注的配置类(相当于原xml配置文件)上标注@ComponentScan(value = "com.xxx")
里面可以添加excludeFilters = {} 、includeFilters = {}等用于过滤,@ComponentScans(value= {@ComponentScan})可以写多个。

4.@Filter

在上面说到的excludeFilters、includeFilters数组中可以添加@Filter注解的过滤器。如

excludeFilters = {
    @Filter(type=FilterType.Annotation,classes={Controller.class,Service.class},useDefaultFilters=false)
}
includeFilters = {
    @Filter(type=FilterType.Annotation,classes={Controller.class,Service.class})
}

5.@Scope

@Bean将实例注入IOC时,可以通过@Scope设置4种模式。
singleton(单例)、prototype(原型)、request(同一个请求一个实例)、session(同一个会话一个实例)。默认是单例,对象为启动时创建,为饿汉式。若设置为prototype则对象为每次获取时创建,为懒汉式。

6.@Lazy

单实例bean可以标注此注解,用于将默认的饿汉式变为懒加载即第一次获取对象时创建。

7.@Conditional

这个注解根据条件来注册bean,可以放在方法上或者类上(满足条件类中的所有都会生效),下面是例子:

// 配置类
@Configuration
public class MainConfig {
    @Bean("sunwukong")
    @Conditional({LinuxCondition.class})
    public Person persion01(){
        return Person.builder().name("孙悟空").age(18).build();
    }

    @Bean("zhubajie")
    @Conditional({WindowsCondition.class})
    public Person persion02(){
        return Person.builder().name("猪八戒").age(17).build();
    }
}
// 自定义condition条件
public class LinuxCondition implements Condition {
    @Override
    public boolean matches(ConditionContext ctx, AnnotatedTypeMetadata annotatedTypeMetadata) {
        Environment env = ctx.getEnvironment();
        String osName = env.getProperty("os.name");
        return osName.contains("Windows");
    }
}
// 自定义condition条件
public class WindowsCondition implements Condition {
    @Override
    public boolean matches(ConditionContext ctx, AnnotatedTypeMetadata annotatedTypeMetadata) {
        Environment env = ctx.getEnvironment();
        String osName = env.getProperty("os.name");
        return osName.contains("Linux");
    }
}

8. @Import

自己写的组件使用@Component``@Controller``@Service``@Dao来标注
第三方的组件使用@Bean来注册
如果嫌写@Bean麻烦,可以使用@Import直接导入组件,默认id为全类名。@Import({A.class,B.class})参数可以是数组同时导入多个类。

image.png

9.@Import通过ImportSelector注册bean

可以自定义导入什么样的组件。

// 自定义importSelect
public class MyImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        // annotationMetadata参数可以获取注解等值
        // 不要返回null
        return new String[]{"com.zmz.al.bean.Red","com.zmz.al.bean.Yellow"};
    }
}
// 配置类中注解导入
@Import({Color.class, MyImportSelector.class})
image.png

10.@Import通过BeanDefinitions手动注册

自定义一个MyBeanDefinationRegistrar

public class MyBeanDefinationRegistrar implements ImportBeanDefinitionRegistrar {

    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        // 判断是否含有黄色以及红色,有的话添加绿色
        boolean hasYellow = registry.containsBeanDefinition("com.zmz.al.bean.Yellow");
        boolean hasRed = registry.containsBeanDefinition("com.zmz.al.bean.Red");
        if (hasYellow && hasRed) {
            // 创建一个beanDefination
            RootBeanDefinition green = new RootBeanDefinition(Green.class);
            // 可以设置bean的name
            registry.registerBeanDefinition("green",green);
        }
    }
}

配置类@import中加入MyBeanDefinationRegistrar.class

@Import({Color.class, MyImportSelector.class, MyBeanDefinationRegistrar.class})
image.png

11.通过BeanFatory注册

// 新建一个类实现一个FacotryBean的接口
public class ColorFactoryBean implements FactoryBean {

    @Override
    public Color getObject() throws Exception {
        return new Color();
    }

    @Override
    public Class getObjectType() {
        return Color.class;
    }

    @Override
    public boolean isSingleton() {
        // true为单例,false为原型
        return true;
    }
}
// 将这个新的类注册到IOC容器
    @Bean
    public ColorFactoryBean colorFactoryBean(){
        return new ColorFactoryBean();
    }
// 测试类
    @Test
    public void registryTest(){
        AnnotationConfigApplicationContext ioc = new AnnotationConfigApplicationContext(MainConfig.class);
        String[] beanDefinitionNames = ioc.getBeanDefinitionNames();
        for (String name : beanDefinitionNames) {
            System.out.println(name);
        }
    }

可以看到,使用ioc可以根据name获取bean,如果有&符号表示获取的是工厂本身,如果不加&符号则获取的是具体的对象。

image.png

12. @PostConstruct

bean的生命周期的控制注解,在bean创建之后,赋值之后,进行调用。

13. @PreDestroy

bean的生命周期的控制注解,在bean的销毁之前进行调用。

@Component
public class Dog {
    private String name;
    private Integer age;

    @PostConstruct
    public void postConstruct(){
        System.out.println("dog postConstruct ...");
    }

    @PreDestroy
    public void preDestroy(){
        System.out.println("dog preDestroy...");
    }
}

14.使用BeanPostProcessor控制bean的生命周期

// 新建一个dog类
public class Dog {
    private String name;
    private Integer age;

    @PostConstruct
    public void postConstruct(){
        System.out.println("dog postConstruct ...");
    }

    @PreDestroy
    public void preDestroy(){
        System.out.println("dog preDestroy...");
    }

    public void init(){
        System.out.println("dog init...");
    }
    public void destroy(){
        System.out.println("dog destroy...");
    }
}
// 配置类中@Bean注册dog bean并标明init、destroy方法
    @Bean(name = "dog",initMethod = "init",destroyMethod = "destroy")
    public Dog dog(){
        return new Dog();
    }
// 构建beanProcessor类
@Component
public class MyBeanProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("初始化前处理beanName:"+beanName+",bean:"+bean);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("初始化后处理beanName:"+beanName+",bean:"+bean);
        return bean;
    }
}

image.png

最后的执行顺序为postProcessBeforeInitializationpostConstructinitpostProcessAfterInitializationpreDestroydestroy

15.@Value

给bean赋值,1)可以是基本数值;2)可以使用Spring表达式SPEL,#{};3)使用${}读取配置文件中的值或者运行环境变量中的值。可以放在全局变量或者方法参数上。

16.PropertySource(value="classpath:person.properties")

使用该注解加载外部配置文件保存到运行的环境变量中,然后再使用@Value读取配置文件。


17. @Autowired@Qualifier

默认按照类型去寻找IOC容器中的组件。如何同一类型的找到了多个,那么默认就根据属性名去寻找,如private ADAO aDao;就根据aDao这个名称去寻找。还可以显示的指定使用@Qualifier("aDao")注解来指定具体的名字。如何IOC中没有这个组件的情况下,可以在@Autowired(required=false)标明是非必须的。
@Autowired可以标注在方法上,表示其中的参数会通过类型去IOC中找到对应的bean。如set方法,有参构造器方法。
还可以标注在参数上public void aaa(@Autowired A a){},标在有参构造器上如果参数为1个时,可以省略。
@Bean时方法中的参数也可以省略@autowired注解,自动会去IOC容器中寻找bean。

18.@Primary

注册bean时,同类型多个bean中可以在其中一个标明此注解,来作为一个首选项,这样依赖注入@Autowired的时候就可以优先拿到首选的bean了。注意@Qualifier优先级大于@Primary

19.@Resource

是Java规范的依赖注入的注解,而@Autowired是Spring的注解。
@Resource默认按照组件名称进行装配。或者显示的@Resource(name="aDao")来指定具体的bean。不能结合@Qualifier@Primary注解,且不能使用required=false属性。

20.@Inject

是Java规范的依赖注入的注解,但是使用时需要引入一个javax.inject的包。

21.Spring底层Aware的使用

自定义组件想要使用Spring底层的组件时,可以实现xxxAware接口再进行使用。


image.png

22.@Profile

可以添加在方法上或者类上。
给组件添加标识,满足条件的bean才能被注册到IOC容器之中。默认@Profile("default")的会被注册。
1)使用配置文件中的spring.prifiles.active=xxx来指定现在使用的环境标识,
2)通过JVM参数-Dspring.prifiles.active=xxx来指定
3)使用编码来指定

// 先准备两个环境的Bean
@Configuration
public class ProfileConfig {

    @Profile("eat")
    @Bean
    public Person baigujing(){
        return new Person("白骨精",17);
    }

    @Profile("mary")
    @Bean
    public Person nverguoguowang(){
        return new Person("女儿国国王",18);
    }

    @Profile("mary")
    @Bean
    public Person kongquegongzhu(){
        return new Person("孔雀公主",16);
    }
}
// 测试类中
public class ProfileTest {
    @Test
    public void profileTest(){
        AnnotationConfigApplicationContext ioc = new AnnotationConfigApplicationContext();
        ioc.getEnvironment().setActiveProfiles("mary");
        ioc.register(ProfileConfig.class);
        ioc.refresh();

        String[] names = ioc.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
    }
}
image.png

可以看到“eat组”的白骨精没有注册进来,“mary组”的孔雀公主、女儿国国王注册进来了。

23. aop相关注解

1.切面类与被切的业务逻辑类都应该使用IOC容器管理
2.给切面类一个注解@Aspect标记为切面类
3.切面类中使用注解@Pointcut("execution(public int com.zmz.al.util.MathUtil.*(..))")编写切入点表达式来赋值切入点的位置
4.@Before("pointCut()")@After("com.zmz.al.log.LogAspect.pointCut()")@AfterReturning(value="pointCut()",returning = "ret")@AfterThrowing(value="pointCut()",throwing = "e")
来编写切入点的前、后、返回后、异常后的生命周期自定义函数。
5.自定义的生命周期函数可以使用JoinPoint jp来获取切点相关的参数,如函数名称、函数参数列表等,这个参数一定要写在参数列表的第一位,还可以在注解中传入value、returning、throwing等属性值。
6.@EnableAspectJAutoProxy // 开启切面自动代理,一般在配置类中开启切面自动代理功能

@Aspect
public class LogAspect {
    // 切入点表达式
    @Pointcut("execution(public int com.zmz.al.util.MathUtil.*(..))")
    public void pointCut(){}

    @Before("pointCut()")
    public void logStart(JoinPoint jp){
        Object[] args = jp.getArgs();
        System.out.println(jp.getSignature().getName()+"@Before运行,参数列表是:"+ Arrays.asList(args));
    }

    @After("com.zmz.al.log.LogAspect.pointCut()")
    public void logEnd(JoinPoint jp){
        System.out.println(jp.getSignature().getName()+"@After运行");
    }

    @AfterReturning(value="pointCut()",returning = "ret")
    public void logReturn(JoinPoint jp,Object ret){
        System.out.println(jp.getSignature().getName()+"@AfterReturning运行正常返回,结果是:"+ret);
    }

    @AfterThrowing(value="pointCut()",throwing = "e")
    public void logException(JoinPoint jp,Exception e){
        System.out.println(jp.getSignature().getName()+"@AfterThrowing运行异常,异常为:"+e);
    }
}
image.png

24.声明式事务注解

1.将DataSource的事务管理器注册到IOC容器中,整合mybatis时会自动注册。
2.@Transactional在方法上添加、@EnableTransactionManagement在配置类上添加开启事务功能。
3.当方法中报异常时,会调用DataSource的事务管理器自动回滚数据库相关操作。

FAQ

1.在测试@Value注解的时候,报了Could not resolve placeholder '' in value "${}"这样的错

进一步检查发现配置文件没有打包进入到target目录,查找之后是因为自己在pom.xml文件中配置了这个导致的。

pom

而这这个标签是用来指示idea将该模块打包成pom,所以,项目在启动编译时没有把配置文件同步到target目录下,项目运行时也拿不到配置文件的信息。

你可能感兴趣的:(Spring注解整理)