网上关于基于Spring自定义注解的文章已经不少了,这篇是我自己实现的时候的一个笔记。

简单介绍

这篇文章我们实现一个自定义的注解,简单了解一下基于Spring实现注解的基本思路。

开始

准备注解

怎么建项目就不用说了,但凡已经开始了解自定义注解的应该都会了。自定义注解当然开始就是准备一个注解了

import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SampleAnnotation {
    // 表示是哪个应用
    String group();

    // 表示是哪个文件
    String file();
}

1、@Target这行说明我们自定义的注解只能使用在方法上,其他选项请自行脑补,不展开了。
2、@Retention这行说明我们的注解要保留到运行时,其他选择可以只保留到编译时,一样自行脑补。

所以我们现在定义的是一个能在方法上加的、运行时依然存在的、有两个属性(group、name)的 注解。
所以我们使用的时候就是在一个方法上添加 @SampleAnnotation(group = “app1”, file = “xxx.properties”)

处理逻辑

注解定义了其实没有什么用,加上之后啥效果都没有,重点是我们怎么处理这个注解。
Spring给我们提供了一个扩展BeanPostProcessor,也叫前后置处理器,我们可以用它在bean初始化前后处理一些东西。
我们这次是要在bean初始化之后做些事情。

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.util.*;

public class SampleBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        Class<?> clazz = bean.getClass();

        Method[] methods = clazz.getMethods();

        for (Method method : methods) {
            Annotation annotation = method.getAnnotation(SampleAnnotation.class);
            if (annotation != null) {
                try {
                    // 开始执行这个有注解的方法
                    method.invoke(bean, new HashMap<>());
                } catch (Exception e) {
                    e.printStackTrace();
                    throw new RuntimeException("执行错误");
                }

//                throw new RuntimeException("这个是测试的,如果抛出异常,spring初始化就会停止,可以快速发现问题");
            }
        }
        return bean;
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }
}

postProcessAfterInitialization方法是我们这次的重点,这个方法会在bean初始化完成之后执行,我们实现的功能是取出所有public修饰的含有SampleAnnotation注解的方法,然后执行它。

配置

然后这个SampleBeanPostProcessor是要配置为一个bean的

<bean id="sampleBeanPostProcessor" class="li.dongpo.tc.service.SampleBeanPostProcessor" />

测试代码

public class Application {
    public static void main(String[] args) throws InterruptedException {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        System.out.println("context初始化完成,开始获取bean");
    }
}

执行输出

拉取到配置文件 {}
context初始化完成,开始获取bean

代码

我把代码上传到了github上,感兴趣的同学可以自行下载参照。 https://github.com/remainer-com/spring-sample 参见 spring-annotation-sample 模块