1. 注解基础
- @Before
先看@Before源码
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Before {
/**
* 指定切点的位置
*/
String value();
/**
* 获取目标方法的参数和对应的值,比较难理解
*/
String argNames() default "";
}
代码示例如下:
public interface Waiter {
void serveTo(String clientName);
void greetTo(String clientName);
void greetTo(String a,String b);
}
public class NaiveWaiter implements Waiter {
@Override
public void serveTo(String clientName) {
System.out.println("serveTo:"+clientName);
}
@Override
public void greetTo(String clientName) {
System.out.println("greetTo:"+clientName);
}
@Override
public void greetTo(String a, String b) {
System.out.println("NaiveWaiter.greetTo:"+a+" "+b);
}
}
public class NaughtWaiter implements Waiter {
@Override
public void serveTo(String clientName) {
System.out.println("NaughtWaiter.serveTo:"+clientName);
}
@NeedTest
@Override
public void greetTo(String clientName) {
System.out.println("NaughtWaiter.greetTo:"+clientName);
}
@NeedTest
@Override
public void greetTo(String a,String b) {
System.out.println("NaughtWaiter.greetTo:"+a+" "+b);
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.METHOD})
public @interface NeedTest {
}
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class TestAspect {
@Before(value = "@annotation(com.ghq.cloud.anno.NeedTest) && args(a,b)",argNames="a,b")
public void needTestFun(String a, String b){
System.out.println("TestAspect.needTestFun:"+a+" "+b);
}
}
说明:
- @Before(value = “@annotation(com.ghq.cloud.anno.NeedTest) && args(a,b)”,argNames=“a,b”)
- 这里的 @annotation(com.ghq.cloud.anno.NeedTest) 表示声明有@NeedTest注解
- 这里的 && 表示 并且 连接符
- 这里的 args(a,b) 表示方法有两个参数,
- argNames=“a,b”,表示参数名字为 a,b,顺序必须一直,切面里面的方法的参数名(这里为 TestAspect #needTestFun)必须为a 和 b
- 目标方法 的参数类型必须 和 切面里面的方法的参数类型保持一致,否则不能增强。参数名字不必和 切面里面的方法的参数名字保持一致。
main方法:
public class AnnoTest {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("classpath:anno.xml");
Waiter naiveWaiter = (Waiter) context.getBean("naiveWaiter");
Waiter naughtWaiter = (Waiter) context.getBean("naughtWaiter");
naiveWaiter.greetTo("snow","xxx");
naughtWaiter.greetTo("aaaaaa","bbbbb");
}
}
输出结果:只有NaughtWaiter #void greetTo(String a,String b)方法增强了
NaiveWaiter.greetTo:snow xxx
TestAspect.needTestFun:aaaaaa bbbbb
NaughtWaiter.greetTo:aaaaaa bbbbb
- @AfterReturning
源码:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AfterReturning {
/**
* 切点表达式:增强绑定的位置
*/
String value() default "";
/**
* 切点表达式:增强绑定的位置 ,当指定了pointcut,将覆盖
*/
String pointcut() default "";
/**
* The name of the argument in the advice signature to bind the returned value to
*/
String returning() default "";
/**
* 同@Before
*/
String argNames() default "";
}
使用:
@AfterReturning(pointcut = "@annotation(com.ghq.cloud.anno.NeedTest)",returning = "ret")
public void testAfterReturning(Object ret){//Joinpoint joinpoint,
System.out.println("bb");
System.out.println(ret+" "+"bb");
}
注意:目标方法抛出异常之后,增强不会执行。可以该表目标方法的返回引用的属性值。
- @After
/*@After(value = "@annotation(com.ghq.cloud.anno.NeedTest) && args(a,b) ",argNames="a,b")
public void testAfterReturning(String a, String b){
System.out.println("bb");
}*/
@After(value = "@annotation(com.ghq.cloud.anno.NeedTest)")
public void testAfterReturning(){
System.out.println("bb");
}
注意:目标方法抛出异常之后,增强会执行。不可以改变目标方法的返回值。
- @Around 略去
- @AfterThrowing 略去
- @DeclareParents 相当于引介增强,案例说明如何使用
示例
public interface Waiter {
void serveTo(String clientName);
void greetTo(String clientName);
}
public class NaiveWaiter implements Waiter {
@Override
public void serveTo(String clientName) {
System.out.println("serveTo:"+clientName);
}
@Override
public void greetTo(String clientName) {
System.out.println("greetTo:"+clientName);
}
}
想法:希望 NaiveWaiter 也能充当售货员的角色,即通过切面技术为 NaiveWaiter 新增 Seller 接口的实现
/**
* 想法:希望 NaiveWaiter 也能充当售货员的角色,
* 即通过切面技术为 NaiveWaiter 新增 Seller 接口的实现
*/
@Aspect
public class EnableSellerAspect {
/**
* @DeclareParents:引介增强,相当于 IntroductionInterceptor
* value : 该成员用于定义切点,它表示在哪个目标类上添加引介增强
* defaultImpl:默认的接口实现类
*/
@DeclareParents(value = "com.ghq.cloud.anno.NaiveWaiter",defaultImpl = SmartSeller.class)
public Seller seller;//要实现的目标接口
}
xml配置:
<aop:aspectj-autoproxy/>
<bean id="naiveWaiter" class="com.ghq.cloud.anno.NaiveWaiter"/>
<bean class="com.ghq.cloud.anno.EnableSellerAspect"/>
main方法:
public class AnnoTest {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("classpath:anno.xml");
Waiter naiveWaiter = (Waiter) context.getBean("naiveWaiter");
naiveWaiter.greetTo("snow");
Seller seller = (Seller) naiveWaiter;
seller.sell("apple");
}
}
输出结果:
greetTo:snow
sell:apple
说明:Seller seller = (Seller) naiveWaiter; 转换成功,Waiter naiveWaiter 自动实现了Seller接口
完。