Spring中@within与@target的一些区别

本文探讨了Spring中@within和@target注解的区别,主要应用于动态切换数据源的场景。通过示例展示了如何在父类和子类上使用这两种注解,并分析了它们在通知方法中获取注解值的不同。@within关注的是调用方法所在类的注解,而@target则关注运行时方法所属类的注解。文章还讨论了如何避免不相关类被错误地代理,并给出了相应的解决方案。
摘要由CSDN通过智能技术生成

背景

项目里有一个动态切换数据源的功能,我们是用切面来实现的,是基于注解来实现的,但是父类的方法是可以切换数据源的,如果有一个类直接继承这个类,调用这个子类时,这个子类是不能够切换数据源的,除非这个子类重写父类的方法。

模拟项目例子

注解定义:
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface MyAnnotation {
    String value() default "me";
}

切面定义:
@Order(-1)
@Aspect
@Component
public class MyAspect {
    @Before("@within(myAnnotation)")
    public void switchDataSource(JoinPoint point, MyAnnotation myAnnotation) {
        System.out.println("before, myAnnotation.value : " + myAnnotation.value());
    }
}

父类Bean:
@MyAnnotation("father")
public class Father {
    public void hello() {
        System.out.println("father.hello()");
    }
    public void hello2() {
        System.out.println("father.hello2()");
    }
}

子类Bean:
@MyAnnotation("son")
public class Son extends Father {
    @Override
    public void hello() {
        System.out.println("son.hello()");
    }
}

配置类:
@Configuration
@EnableAspectJAutoProxy(exposeProxy = true)
public class Config {

    @Bean
    public Father father() {
        return new Father();
    }

    @Bean
    public Son son() {
        return new Son();
    }
}

测试类:
public class Main {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class,
                MyAspect.class);
        Father father = context.getBean("father", Father.class);
        father.hello();
        father.hello2();
        Son son = context.getBean(Son.class);
        son.hello();
        son.hello2();
    }
}

我们定义了一个@Before通知,方法参数有point, myAnnotation,方法里输出了myAnnotation.value的值

下面是输出结果:

before, myAnnotation.value : father
father.hello()
before, myAnnotation.value : father
father.hello2()
before, myAnnotation.value : son
son.hello()
before, myAnnotation.value : father
father.hello2()

从上面的输出结果看出:Son类重写了hello方法,myAnnotation.value的输出的值是sonhello2方法没有重写,myAnnotation.value的输出的值是father

根据需求,我们肯定希望调用Son类的所有方法时,都希望myAnnotation.value的输出的值是son,因此就需要重写父类的所有public方法

那有没有办法不重写这些方法也能达到相同的效果呢,答案是可以的。

看看使用@within@target的区别

我们分别在父类和子类上加上注解和去掉注解,一起来看看对应的结果

@within

父类无注解,子类有注解:

father.hello()
father.hello2()
before, myAnnotation.value : son
son.hello()
father.hello2()

父类有注解,子类无注解:

before, myAnnotation.value : father
father.hello()
before, myAnnotation.value : father
father.hello2()
before, myAnnotation.value : father
son.hello()
before, myAnnotation.value : father
father.hello2()

父类有注解,

Java8新特性及实战视频教程完整版Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。Stream 使用一种类似用 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。这种风格将要处理的元素集合看作一种流, 流在管道传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。元素流在管道经过间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。 Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法)。使用Lambda 表达式可以使代码变的更加简洁紧凑。Java8实战视频-01让方法参数具备行为能力Java8实战视频-02Lambda表达式初探Java8实战视频-03Lambda语法精讲Java8实战视频-04Lambda使用深入解析Java8实战视频-05Lambda方法推导详细解析-上.wmvJava8实战视频-06Lambda方法推导详细解析-下Java8实战视频-07Stream入门及Stream在JVM的线程表现Java8实战视频-08Stream知识点总结Stream源码阅读Java8实战视频-09如何创建Stream上集Java8实战视频-10如何创建Stream下集.wmvJava8实战视频-11Stream之filter,distinct,skip,limit,map,flatmap详细介绍Java8实战视频-12Stream之Find,Match,Reduce详细介绍Java8实战视频-13NumericStream的详细介绍以及和Stream之间的相互转换Java8实战视频-14Stream综合练习,熟练掌握API的用法Java8实战视频-15在Optional出现之前经常遇到的空指针异常.wmvJava8实战视频-16Optional的介绍以及API的详解Java8实战视频-17Optional之flatMap,综合练习,Optional源码剖析Java8实战视频-18初识Collector体会Collector的强大Java8实战视频-19Collector使用方法深入详细介绍-01Java8实战视频-20Collector使用方法深入详细介绍-02Java8实战视频-21Collector使用方法深入详细介绍-03.wmvJava8实战视频-22Collector使用方法深入详细介绍-04Java8实战视频-23Collector原理讲解,JDK自带Collector源码深度剖析Java8实战视频-24自定义Collector,结合Stream的使用详细介绍Java8实战视频-25Parallel Stream编程体验,充分利用多核机器加快计算速度Java8实战视频-26Fork Join框架实例深入讲解Java8实战视频-27Spliterator接口源码剖析以及自定义Spliterator实现一个Stream.wmvJava8实战视频-28Default方法的介绍和简单的例子Java8实战视频-29Default方法解决多重继承冲突的三大原则详细介绍Java8实战视频-30多线程Future设计模式原理详细介绍,并且实现一个Future程序Java8实战视频-31JDK自带Future,Callable,ExecutorService介绍Java8实战视频-32实现一个异步基于事件回调的Future程序.wmvJava8实战视频-33CompletableFuture用法入门介绍Java8实战视频-34CompletableFuture之supplyAsync详细介绍Java8实战视频-35CompletableFuture流水线工作,join多个异步任务详细讲解Java8实战视频-36CompletableFuture常用API的重点详解-上Java8实战视频-37CompletableFuture常用API的重点详解-下Java8实战视频-38JDK老DateAPI存在的问题,新的DateAPI之LocalDate用法及其介绍.wmvJava8实战视频-39New Date API之LocalTime,LocalDateTime,Instant,Duration,Period详细介绍Java8实战视频-40New Date API之format和parse介绍
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值