注解的继承验证

今天遇到一个问题,就是我们对外暴露的接口方法需要加一个注解,这个注解是在实现类的方法上加还是在接口的方法签名前加,我看代码规范都是写在实现类的方法上。我挺好奇接口签名上能反射拿到么。遂写了个demo验证下我的想法。


@SpringBootApplication
public class Test {
    public static void main(String[] args) {
        SpringApplication.run(Test.class);
    }

}

@org.springframework.context.annotation.Configuration
class Configuration {

    @Bean
    public BeanLoading beanLoading() {
        return new BeanLoading();
    }

}

// 拿接口的注解
@Component
class ApplicationStartedListener implements ApplicationListener<ApplicationStartedEvent> {
    @Override
    public void onApplicationEvent(ApplicationStartedEvent applicationStartedEvent) {
        ConfigurableApplicationContext applicationContext = applicationStartedEvent.getApplicationContext();
        UserService userService = applicationContext.getBean(UserService.class);


        if (userService.getClass().isAnnotationPresent(TestClassAnnotation.class)) {
            System.out.println("find class annotation");
        }

        Method[] methods = userService.getClass().getMethods();
        for (Method method : methods) {
            if (AnnotationUtils.findAnnotation(method, TestMethodAnnotation.class) != null) {
                System.out.println("find TestMethodAnnotation !! ");
                return ;
            }
        }
        System.out.println("not find TestMethodAnnotation!!");
    }
}

class BeanLoading implements BeanPostProcessor {
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("bean loaded after " + beanName);
        return bean;
    }
}

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface TestMethodAnnotation {

}


interface UserService {

    @TestMethodAnnotation
    void say();
}

@Component
class UserServiceImpl implements UserService {

//    @TestMethodAnnotation
    @Override
    public void say() {

    }
}

输出结果:find TestMethodAnnotation !!
实验证明,在父方法签名加和子类签名加效果是一样的,这个问题本质其实是一个方法注解的问题。拍拍脑袋就有两个问题,父类的方法注解能继承么,类注解能继承么。如果方法能继承,那类上是怎样的结果呢.

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@interface TestClassAnnotation {

}
@TestClassAnnotation
interface UserService {

    @TestMethodAnnotation
    void say();
}

@Component
class UserServiceImpl implements UserService {

//    @TestMethodAnnotation
    @Override
    public void say() {

    }
}

not find class anotation !!

这并不能获取到类上的注解。

于是我在注解上添加inherited注解:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@interface TestClassAnnotation {

}

依然是 not find class anotation !!.
后来看到:

Note that this meta-annotation type has no effect if the annotated
 * type is used to annotate anything other than a class.  Note also
 * that this meta-annotation only causes annotations to be inherited
 * from superclasses; annotations on implemented interfaces have no
 * effect.

也就是说对接口是无效的。
把UserService改成抽象类即能识别到对应类的注解。

@SpringBootApplication
public class Test {
    public static void main(String[] args) {
        SpringApplication.run(Test.class);
    }

}

@org.springframework.context.annotation.Configuration
class Configuration {

    @Bean
    public BeanLoading beanLoading() {
        return new BeanLoading();
    }

}

// 拿接口的注解
@Component
class ApplicationStartedListener implements ApplicationListener<ApplicationStartedEvent> {

    @Override
    public void onApplicationEvent(ApplicationStartedEvent applicationStartedEvent) {
        ConfigurableApplicationContext applicationContext = applicationStartedEvent.getApplicationContext();
        UserService userService = applicationContext.getBean(UserService.class);

        if (userService.getClass().isAnnotationPresent(TestClassAnnotation.class)) {
            System.out.println("find class annotation !!");
        } else {
            System.out.println("not find class anotation !!");
        }

        Method[] methods = userService.getClass().getMethods();
        for (Method method : methods) {
            if (AnnotationUtils.findAnnotation(method, TestMethodAnnotation.class) != null) {
                System.out.println("find TestMethodAnnotation !! ");
                return ;
            }
        }
        System.out.println("not find TestMethodAnnotation!!");
    }
}

class BeanLoading implements BeanPostProcessor {
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("bean loaded after " + beanName);
        return bean;
    }
}

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface TestMethodAnnotation {

}

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@interface TestClassAnnotation {

}


@TestClassAnnotation
class UserService {

    @TestMethodAnnotation
    void say() {

    }
}

@Component
class UserServiceImpl extends UserService {

//    @TestMethodAnnotation
    @Override
    public void say() {

    }
}

即可识别到基类的注解。


这个问题本质上是注解继承问题,还有一些复杂场景,例如抽象方法的重写,以及字段注解继承等等问题,网上有很多其他资料,也可以根据上面的的代码自己改改验证会更加深刻。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值