Spring中@within与@target的一些区别,从入门到精通

文章讲述了在SpringAOP中,如何使用@Within和@Target注解来控制切面通知的方法行为,尤其是在父子类继承场景下,理解这两个注解的差异以实现期望的行为:当子类重写方法时,确保@Annotation的值指向子类而非父类。
摘要由CSDN通过智能技术生成

父类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()

父类有注解,子类有注解(其实就是上面那个例子的结果):

before, myAnnotation.value : father

father.hello()

before, myAnnotation.value : father

father.hello2()

before, myAnnotation.value : son

son.hello()

before, myAnnotation.value : father

father.hello2()

@target

把切面代码改成如下:

@Order(-1)

@Aspect

@Component

public class MyAspect {

@Before(“@target(myAnnotation)”)

public void switchDataSource(JoinPoint point, MyAnnotation myAnnotation) {

System.out.println("before, myAnnotation.value : " + myAnnotation.value());

}

}

我们再一起来看看测试结果:

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

father.hello()

father.hello2()

before, myAnnotation.value : son

son.hello()

before, myAnnotation.value : son

father.hello2()

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

before, myAnnotation.value : father

father.hello()

before, myAnnotation.value : father

father.hello2()

son.hello()

father.hello2()

父类有注解,子类有注解

before, myAnnotation.value : father

father.hello()

before, myAnnotation.value : father

father.hello2()

before, myAnnotation.value : son

son.hello()

before, myAnnotation.value : son

father.hello2()

我们从上面总结出一套规律:

@within@Before通知方法的myAnnotation参数指的是调用方法所在的类上面的注解,就是这个方法是在哪个类上定义的

@target@Before通知方法的myAnnotation参数指的是调用方法运行时所属于的类上面的注解

我们最后总结一下,如果父类和子类上都标有注解,@within@target的所得到实际注解的区别

| | @within | @target |

| — | — | — |

| 父类方法 | 父类注解 | 父类注解 |

| 子类不重写方法 | 父类注解 | 子类注解 |

| 子类重写方法 | 子类注解 | 子类注解 |

@target 看起来跟合理一点

从上面的分析可以看出,其实用@target更符合我们想要的结果,在某个类上面加一个注解,拦截的时候就会获取这个类上面的注解,跟父类完全没有关系了

但这个时候会遇到一个问题,就是不相关的类都会生从代理类,

例子如下:

public class NormalBean {

public void hello() {

}

}

@Configuration

@EnableAspectJAutoProxy(exposeProxy = true)

public class Config {

@Bean

public Father father() {

return new Father();

}

@Bean

public Son son() {

return new Son();

}

@Bean

public NormalBean normalBean() {

return new NormalBean();

}

}

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();

NormalBean normalBean = context.getBean(NormalBean.class);

System.out.println(normalBean.getClass());

}

}

输出:

class cn.eagleli.spring.aop.demo.NormalBean E n h a n c e r B y S p r i n g C G L I B EnhancerBySpringCGLIB EnhancerBySpringCGLIBeebc2a39

可以看出NormalBean自己什么都没做,但却被代理了

我们再把@target换成@within

class cn.eagleli.spring.aop.demo.NormalBean

可以看出使用@within时,不相关的类没有被代理

我们一起来看看为什么

AbstractAutoProxyCreator类中的wrapIfNecessary方法打断点,看看什么情况:

@within

@target

我们从上面的图片就可以理解为什么@target会生成代理类

我们再深入看一下:

@within会走到如下:

public class ExactAnnotationTypePattern extends AnnotationTypePattern {

@Override

public FuzzyBoolean matches(AnnotatedElement annotated, ResolvedType[] parameterAnnotations) {

// …

}

}

小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Java工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Java开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频

如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
img

最后

为什么我不完全主张自学?
平台上的大牛基本上都有很多年的工作经验了,你有没有想过之前行业的门槛是什么样的,现在行业门槛是什么样的?以前企业对于程序员能力要求没有这么高,甚至十多年前你只要会写个“Hello World”,你都可以入门这个行业,所以以前要入门是完全可以入门的。
②现在也有一些优秀的年轻大牛,他们或许也是自学成才,但是他们一定是具备优秀的学习能力,优秀的自我管理能力(时间管理,静心坚持等方面)以及善于发现问题并总结问题。
如果说你认为你的目标十分明确,能做到第②点所说的几个点,以目前的市场来看,你才真正的适合去自学。

除此之外,对于绝大部分人来说,报班一定是最好的一种快速成长的方式。但是有个问题,现在市场上的培训机构质量参差不齐,如果你没有找准一个好的培训班,完全是浪费精力,时间以及金钱,这个需要自己去甄别选择。

我个人建议线上比线下的性价比更高,线下培训价格基本上没2W是下不来的,线上教育现在比较成熟了,此次疫情期间,学生基本上都感受过线上的学习模式。相比线下而言,线上的优势以我的了解主要是以下几个方面:
①价格:线上的价格基本上是线下的一半;
②老师:相对而言线上教育的师资力量比线下更强大也更加丰富,资源更好协调;
③时间:学习时间相对而言更自由,不用裸辞学习,适合边学边工作,降低生活压力;
④课程:从课程内容来说,确实要比线下讲的更加深入。

应该学哪些技术才能达到企业的要求?(下图总结)

都可以入门这个行业,所以以前要入门是完全可以入门的。
②现在也有一些优秀的年轻大牛,他们或许也是自学成才,但是他们一定是具备优秀的学习能力,优秀的自我管理能力(时间管理,静心坚持等方面)以及善于发现问题并总结问题。
如果说你认为你的目标十分明确,能做到第②点所说的几个点,以目前的市场来看,你才真正的适合去自学。

除此之外,对于绝大部分人来说,报班一定是最好的一种快速成长的方式。但是有个问题,现在市场上的培训机构质量参差不齐,如果你没有找准一个好的培训班,完全是浪费精力,时间以及金钱,这个需要自己去甄别选择。

我个人建议线上比线下的性价比更高,线下培训价格基本上没2W是下不来的,线上教育现在比较成熟了,此次疫情期间,学生基本上都感受过线上的学习模式。相比线下而言,线上的优势以我的了解主要是以下几个方面:
①价格:线上的价格基本上是线下的一半;
②老师:相对而言线上教育的师资力量比线下更强大也更加丰富,资源更好协调;
③时间:学习时间相对而言更自由,不用裸辞学习,适合边学边工作,降低生活压力;
④课程:从课程内容来说,确实要比线下讲的更加深入。

应该学哪些技术才能达到企业的要求?(下图总结)

[外链图片转存中…(img-1eFtwuyi-1711157826699)]

[外链图片转存中…(img-tex5lLZP-1711157826699)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

  • 15
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值