Spring Aspect Demo
前面已经简单介绍了 JDK 和 CGLIB 动态代理的实现,下面继续看下 Spring关于 AOP 的应用
一 实现方式
1.ProxyFactory
基于 MethodBeforeAdvice、AfterReturningAdvice 利用 Spring Api 定义前、后置处理方法,并通过代理工厂类获取代理对象(代码或Xml配置实现)
2.ProxyFactoryBean
显式地设置 Advisors、Advice、Target等(基于代理的AOP ),从容器内获得的就是代理对象;Advice 和 CutPoint 也可以由 IOC 管理
3.AspectJProxyFactory
基于注解的形式:@Aspect、@PointCut、@Before、@Around、@After、@AfterRunning、@AfterThrowing
二 代码测试
1.Spring ProxyFactory
Pom 依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.demo</groupId>
<artifactId>aop</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.7.4</version>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-aop</artifactId>-->
<!-- <version>2.7.4</version>-->
<!-- </dependency>-->
</dependencies>
</project>
前置增强API
package com.demo.moon.api;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
/**
* @author
* @date 2022-10-03 11:25
* @since 1.8
*/
public class RabbitBeforeApi implements MethodBeforeAdvice {
/**
* 前置执行
* @param method
* @param args
* @param target
* @throws Throwable
*/
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("准备青草...");
}
}
后置增强 API
package com.demo.moon.api;
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
/**
* @author
* @date 2022-10-03 11:31
* @since 1.8
*/
public class RabbitAfterApi implements AfterReturningAdvice {
/**
* 后置执行
* @param returnValue
* @param method
* @param args
* @param target
* @throws Throwable
*/
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("打扫兔毛...");
}
}
测试接口
package com.demo.moon.service;
/**
* @author
* @date 2022-10-03 11:23
* @since 1.8
*/
public interface RabbitService {
/**
* 喂养
*/
void feed();
}
测试实现类
package com.demo.moon.service.impl;
import com.demo.moon.service.RabbitService;
/**
* @author
* @date 2022-10-03 11:23
* @since 1.8
*/
public class RabbitServiceImpl implements RabbitService {
@Override
public void feed() {
System.out.println("喂养兔子...");
}
}
测试方法
package com.demo;
import com.demo.moon.api.RabbitAfterApi;
import com.demo.moon.service.RabbitService;
import com.demo.moon.service.impl.RabbitServiceImpl;
import org.springframework.aop.framework.ProxyFactory;
/**
* @author
* @date 2022-10-03 14:10
* @since 1.8
*/
public class AopTest {
public static void main(String[] args) {
//创建被代理类
RabbitServiceImpl target = new RabbitServiceImpl();
//创建代理工厂
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(target);
//添加前后置处理
proxyFactory.addAdvice(new RabbitBeforeApi());
proxyFactory.addAdvice(new RabbitAfterApi());
//获取代理对象
Object proxy = proxyFactory.getProxy();
//调用
((RabbitService)proxy).feed();
}
}
测试效果
改进,通过Lambda表达式添加切面方法:
package com.demo;
import com.demo.moon.api.RabbitAfterApi;
import com.demo.moon.api.RabbitBeforeApi;
import com.demo.moon.service.RabbitService;
import com.demo.moon.service.impl.RabbitServiceImpl;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.framework.ProxyFactory;
import java.lang.reflect.Method;
/**
* @author
* @date 2022-10-03 14:10
* @since 1.8
*/
public class AopTest {
public static void main(String[] args) {
//创建被代理类
RabbitServiceImpl target = new RabbitServiceImpl();
//创建代理工厂
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(target);
//添加前后置处理
proxyFactory.addAdvice(((MethodBeforeAdvice) (method, args1, target1) -> {
System.out.println("我是在准备青草之前添加的...");
}));
proxyFactory.addAdvice(new RabbitBeforeApi());
proxyFactory.addAdvice(new RabbitAfterApi());
proxyFactory.addAdvice(((MethodBeforeAdvice) (method, args1, target1) -> {
System.out.println("我是在准备青草之后添加的...");
}));
//获取代理对象
Object proxy = proxyFactory.getProxy();
//调用
((RabbitService)proxy).feed();
}
}
多个前置处理,按添加顺序执行
2.Spring ProxyFactoryBean
项目结构
通过 Xml 文件配置(同样可以如同上述示例用代码实现)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 被代理类 -->
<bean id="rabbitTarget" class="com.demo.moon.service.impl.RabbitServiceImpl" />
<!-- 前、后置增强 -->
<bean id="rabbitBeforeApi" class="com.demo.moon.api.RabbitBeforeApi" />
<bean id="rabbitAfterApi" class="com.demo.moon.api.RabbitAfterApi" />
<!-- 代理工厂 -->
<bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 指定被代理类 -->
<property name="target" ref="rabbitTarget"/>
<!-- 指定接口名 -->
<property name="proxyInterfaces" value="com.demo.moon.service.RabbitService" />
<!-- 指定 Advice 拦截引用 -->
<property name="interceptorNames">
<list>
<value>rabbitBeforeApi</value>
<value>rabbitAfterApi</value>
</list>
</property>
<!-- 指定代理类生成方式:默认 JDK 此处强制指定为 CGLIB -->
<property name="proxyTargetClass" value="true" />
</bean>
</beans>
测试类
package com.demo;
import com.demo.moon.service.RabbitService;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author
* @date 2022-10-03 14:55
* @since 1.8
*/
public class XmlTest {
public static void main(String[] args) {
//通过指定Xml文件加载上下文
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:/spring.xml");
//启动容器
context.refresh();
//从容器中获取实例
Object proxy = context.getBean("proxyFactoryBean");
//调用
((RabbitService)proxy).feed();
}
}
测试效果
3.Spring AspectJProxyFactory
1.演示
增加依赖
<!-- 主要是为了引入: org.aspect:aspectjweaver:1.9.7 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<version>2.7.4</version>
</dependency>
定义切面类
package com.demo.moon.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
/**
* 定义一个切面类, 添加切面注解
*
* @author
* @date 2022-10-03 16:33
* @since 1.8
*/
@Aspect
public class RabbitAspect {
/**
* 定义切点:当前规则匹配了 RabbitService 的所有方法
*/
@Pointcut("execution(* com.demo.moon.service.RabbitService.*(..))")
public void point(){}
/**
* 针对切入点做前置增强
* @param joinPoint
*/
@Before(value = "point()")
public void before(JoinPoint joinPoint) {
System.out.println("准备青草...");
}
/**
* 针对切入点做前置增强
* @param joinPoint
*/
@After(value = "point()")
public void after(JoinPoint joinPoint) {
System.out.println("打扫兔毛...");
}
}
测试类
package com.demo.moon;
import com.demo.moon.aspect.RabbitAspect;
import com.demo.moon.service.RabbitService;
import com.demo.moon.service.impl.RabbitServiceImpl;
import org.springframework.aop.aspectj.annotation.AspectJProxyFactory;
/**
* @author
* @date 2022-10-03 16:44
* @since 1.8
*/
public class AspectTest {
public static void main(String[] args) {
//创建被代理类
RabbitServiceImpl target = new RabbitServiceImpl();
//创建 AspectJProxyFactory
AspectJProxyFactory proxyFactory = new AspectJProxyFactory();
//设置被代理的目标对象
proxyFactory.setTarget(target);
//设置标注了 @Aspect 注解的类
proxyFactory.addAspect(RabbitAspect.class);
//生成代理对象
RabbitService proxy = proxyFactory.getProxy();
//调用
proxy.feed();
}
}
测试效果
2.切点配置介绍
规则标签 | 用法 |
---|---|
execution | 匹配方法执行的连接点 |
within | 匹配指定类型内的方法 |
this | 匹配当前Aop代理对象类型内的方法;注意是Aop代理对象的类型匹配,包含接口 |
target | 匹配被代理对象的类型内的方法 |
args | 用于匹配当前执行的方法传入的参数为指定类型的执行方法 |
bean | Spring AOP 扩展的,匹配指定名称的 Bean 对象的方法 |
@within | 匹配添加了指定注解类型的类内的方法 |
@target | 匹配被代理对象的类型的类,添加了指定注解的时的方法 |
@args | 匹配当前方法入参,该参数类型的类,添加了指定注解时的方法 |
@annotation | 匹配当前执行方法持有指定注解的方法 |
说明
符号 | 含义 |
---|---|
* | 匹配任意数量字符 |
. . | 匹配任意数量字符的重复: 1.类型模式中匹配任意数量子包 2.方法参数模式中匹配任意数量参数(零 或 多个) |
+ | 匹配指定类型及其子类型;仅能作为后缀放在类型模式后边 |
关于 isAssignableFrom
//RabbitService、RabbitServiceImpl、Parent、Sub 类定义在下文
//A.class.isAssignableFrom(B.class)
//判断 B 是不是 继承于 A
//或者 B 是不是 实现了 A
//继承和实现、同一个类
System.out.println(RabbitServiceImpl.class.isAssignableFrom(RabbitService.class));
System.out.println(Sub.class.isAssignableFrom(Parent.class));
System.out.println(Sub.class.isAssignableFrom(Sub.class));
//继承和实现相反
System.out.println(RabbitService.class.isAssignableFrom(RabbitServiceImpl.class));
System.out.println(Parent.class.isAssignableFrom(Sub.class));
//输出
//false
//false
//true
//true
//true
判断比对
标签 | 判断对象 | 条件(exp 表示配置的类) |
---|---|---|
within | target | target.getClass.equals(exp.class) |
this | proxy | exp.class.isAssignableFrom(proxy.getClass()) |
target | target | exp.class.isAssignableFrom(target.getClass()) |
1.execution
示例
表达式 | 解析 |
---|---|
* com.demo.moon.service.RabbitService.*(. .) | 接口类 RabbitService 的所有方法 |
* com.demo.moon.service.RabbitService.*() | 接口类 RabbitService 的所有无参方法 |
* com.demo.moon.service.RabbitService.*(String) | 接口类 RabbitService 的所有只包含一个 String 参数的方法 |
* com.demo.moon.service.RabbitService.*( *,String) | 接口类 RabbitService 的所有只包含两个参数,且第二个参数类型为 String 的方法 |
* com.demo.moon.service.RabbitService.*( . .,String) | 接口类 RabbitService 的所有最后一个参数类型为 String 的方法 |
2.within
指定类型(全类名)
示例:@Pointcut(“within(com.demo.moon.cut.Parent)”)
父类
package com.demo.moon.cut;
/**
* @author
* @date 2022-10-03 17:52
* @since 1.8
*/
public class Parent {
/**
* 有
* @param count
* @param animal
*/
public void has(int count,String animal){
System.out.println(String.format("有 %s 只 %s ...",count,animal));
}
/**
* 喂养
* @param animal
*/
public void feed(String animal){
System.out.println(String.format("喂养 %s ...",animal));
}
}
子类
package com.demo.moon.cut;
/**
* @author
* @date 2022-10-03 17:52
* @since 1.8
*/
public class Sub extends Parent{
/**
* 做饭
* @param food_one
* @param food_two
* @param food_three
*/
public void cook(String food_one,String food_two,String food_three){
System.out.println(String.format("用 %s、%s、%s ...",food_one,food_two,food_three));
}
}
切面类
package com.demo.moon.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
/**
* @author
* @date 2022-10-03 17:59
* @since 1.8
*/
@Aspect
public class WithInAspect {
@Pointcut("within(com.demo.moon.cut.Parent)")
public void point(){}
@Before(value = "point()")
public void before(JoinPoint joinPoint) {
System.out.println("准备 ...");
}
}
测试类
package com.demo.moon;
import com.demo.moon.aspect.WithInAspect;
import com.demo.moon.cut.Parent;
import org.springframework.aop.aspectj.annotation.AspectJProxyFactory;
/**
* @author
* @date 2022-10-03 17:51
* @since 1.8
*/
public class CutPointTest {
public static void main(String[] args) {
withIn();
}
public static void withIn(){
//创建被代理类
Parent target = new Parent();
//创建 AspectJProxyFactory
AspectJProxyFactory proxyFactory = new AspectJProxyFactory();
//设置被代理的目标对象
proxyFactory.setTarget(target);
//设置标注了 @Aspect 注解的类
proxyFactory.addAspect(WithInAspect.class);
//生成代理对象
Parent proxy = proxyFactory.getProxy();
//调用
proxy.feed("兔子");
}
}
测试效果
如果指定的是子类 Sub 则无法直接生成代理,需要增加扩展符 “+”
@Pointcut("within(com.demo.moon.cut.Parent+)")
package com.demo.moon;
import com.demo.moon.aspect.WithInAspect;
import com.demo.moon.cut.Sub;
import org.springframework.aop.aspectj.annotation.AspectJProxyFactory;
/**
* @author
* @date 2022-10-03 17:51
* @since 1.8
*/
public class CutPointTest {
public static void main(String[] args) {
withIn();
}
public static void withIn(){
//创建被代理类
Sub target = new Sub();
//创建 AspectJProxyFactory
AspectJProxyFactory proxyFactory = new AspectJProxyFactory();
//设置被代理的目标对象
proxyFactory.setTarget(target);
//设置标注了 @Aspect 注解的类
proxyFactory.addAspect(WithInAspect.class);
//生成代理对象
Sub proxy = proxyFactory.getProxy();
//调用
proxy.feed("兔子");
}
}
3.this
全类名匹配,判断生成的代理对象类型是否与 this 指定的类型一致,一致则增强;判断方式:
this(x) -> x.getClass().isAssignableFrom(proxy.getClass());
所以 this 可以直接增强 Sub
切面类
package com.demo.moon.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
/**
* @author
* @date 2022-10-03 18:18
* @since 1.8
*/
@Aspect
public class ThisAspect {
@Pointcut("this(com.demo.moon.cut.Parent)")
public void point(){}
@Before(value = "point()")
public void before(JoinPoint joinPoint) {
System.out.println("准备 ...");
}
}
测试类
package com.demo.moon;
import com.demo.moon.aspect.ThisAspect;
import com.demo.moon.cut.Parent;
import com.demo.moon.cut.Sub;
import org.springframework.aop.aspectj.annotation.AspectJProxyFactory;
/**
* @author
* @date 2022-10-03 17:51
* @since 1.8
*/
public class CutPointTest {
public static void main(String[] args) {
System.out.println(Parent.class.isAssignableFrom(Sub.class));
thisAsp();
}
public static void thisAsp(){
//创建被代理类
Sub target = new Sub();
//创建 AspectJProxyFactory
AspectJProxyFactory proxyFactory = new AspectJProxyFactory();
//设置被代理的目标对象
proxyFactory.setTarget(target);
//设置标注了 @Aspect 注解的类
proxyFactory.addAspect(ThisAspect.class);
//生成代理对象
Sub proxy = proxyFactory.getProxy();
//调用
proxy.feed("兔子");
}
}
测试效果
注意如果是接口和实现类,代理为实现类时,获取接口对象,则代理不生效
@Pointcut("this(com.demo.moon.service.impl.RabbitServiceImpl)")
public static void thisAsp(){
RabbitServiceImpl target = new RabbitServiceImpl();
AspectJProxyFactory proxyFactory = new AspectJProxyFactory(target);
proxyFactory.addAspect(ThisAspect.class);
//proxyFactory.setProxyTargetClass(true);
RabbitService proxy = proxyFactory.getProxy();
System.out.println(RabbitServiceImpl.class.isAssignableFrom(proxy.getClass()));
proxy.feed();
}
这是因为,Aspect 对于接口的实现类默认通过 JDK 方式生成代理类,新生成的对象是一个新的实现类,isAssignableFrom 判断失败;通过
proxyFactory.setProxyTargetClass(true);
强制指定使用CGLIB方式,生成继承类,则可判断通过
4.target
全类名匹配,判断被代理对象类型是否与 target 指定的类型一致,一致则增强;判断方式:
target(x) -> x.getClass().isAssignableFrom(target.getClass());
切面类
package com.demo.moon.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
/**
* @author
* @date 2022-10-03 18:54
* @since 1.8
*/
@Aspect
public class TargetAspect {
@Pointcut("target(com.demo.moon.cut.Sub)")
public void point(){}
@Before(value = "point()")
public void before(JoinPoint joinPoint) {
System.out.println("准备 ...");
}
}
测试类
package com.demo.moon;
import com.demo.moon.aspect.TargetAspect;
import com.demo.moon.cut.Sub;
import org.springframework.aop.aspectj.annotation.AspectJProxyFactory;
/**
* @author
* @date 2022-10-03 17:51
* @since 1.8
*/
public class CutPointTest {
public static void main(String[] args) {
target();
}
public static void target(){
//创建被代理类
Sub target = new Sub();
//创建 AspectJProxyFactory
AspectJProxyFactory proxyFactory = new AspectJProxyFactory();
//设置被代理的目标对象
proxyFactory.setTarget(target);
//设置标注了 @Aspect 注解的类
proxyFactory.addAspect(TargetAspect.class);
//生成代理对象
Sub proxy = proxyFactory.getProxy();
//调用
proxy.feed("兔子");
}
}
测试效果
5.args
匹配方法调用传入的参数类型,并非方法定义参数列表,且 args 配置参数类型不支持通配符;此种方式为根据调用传参动态切入,系统资源开销大,非必要慎用
修改 Sub 类,增加如下方法
/**
* 学习
* @param animal
* @param something
*/
public void learn(String animal,String something){
System.out.println(String.format("%s 学习了 %s ...",animal,something));
}
切面类
package com.demo.moon.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
/**
* @author
* @date 2022-10-03 19:28
* @since 1.8
*/
@Aspect
public class ArgsAspect {
@Pointcut("args(int,String)")
public void point(){}
@Before(value = "point()")
public void before(JoinPoint joinPoint) {
System.out.println("准备 ...");
}
}
测试类
package com.demo.moon;
import com.demo.moon.aspect.ArgsAspect;
import com.demo.moon.cut.Sub;
import org.springframework.aop.aspectj.annotation.AspectJProxyFactory;
/**
* @author
* @date 2022-10-03 17:51
* @since 1.8
*/
public class CutPointTest {
public static void main(String[] args) {
args();
}
public static void args(){
//创建被代理类
Sub target = new Sub();
//创建 AspectJProxyFactory
AspectJProxyFactory proxyFactory = new AspectJProxyFactory();
//设置被代理的目标对象
proxyFactory.setTarget(target);
//设置标注了 @Aspect 注解的类
proxyFactory.addAspect(ArgsAspect.class);
//生成代理对象
Sub proxy = proxyFactory.getProxy();
//调用
proxy.learn("兔子","挖洞");
proxy.has(1,"兔子");
proxy.feed("兔子");
}
}
测试效果
6.@within
注解类型,匹配添加了指定注解的类的方法,配置时获取类注解:
注解类
package com.demo.moon.anno;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author
* @date 2022-10-03 19:57
* @since 1.8
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface RabbitAnnotation {
}
被代理类
package com.demo.moon.cut;
import com.demo.moon.anno.RabbitAnnotation;
/**
* @author
* @date 2022-10-03 19:58
* @since 1.8
*/
@RabbitAnnotation
public class Anno {
/**
* 喂养
*/
public void feed(){
System.out.println("喂养兔子...");
}
}
切面类
package com.demo.moon.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
/**
* @author
* @date 2022-10-03 19:59
* @since 1.8
*/
@Aspect
public class AtWithInAspect {
@Pointcut("@within(com.demo.moon.anno.RabbitAnnotation)")
public void point(){}
@Before(value = "point()")
public void before(JoinPoint joinPoint) {
System.out.println("准备 ...");
}
}
测试类
package com.demo.moon;
import com.demo.moon.aspect.AtWithInAspect;
import com.demo.moon.cut.Anno;
import org.springframework.aop.aspectj.annotation.AspectJProxyFactory;
/**
* @author
* @date 2022-10-03 17:51
* @since 1.8
*/
public class CutPointTest {
public static void main(String[] args) {
atWithIn();
}
public static void atWithIn(){
//创建被代理类
Anno target = new Anno();
//创建 AspectJProxyFactory
AspectJProxyFactory proxyFactory = new AspectJProxyFactory();
//设置被代理的目标对象
proxyFactory.setTarget(target);
//设置标注了 @Aspect 注解的类
proxyFactory.addAspect(AtWithInAspect.class);
//生成代理对象
Anno proxy = proxyFactory.getProxy();
//调用
proxy.feed();
}
}
测试效果
定义一个子类继承其父类,重写父类方法,并添加一个新的方法,观察是否能正常切入
package com.demo.moon.cut;
/**
* @author
* @date 2022-10-03 20:05
* @since 1.8
*/
public class AnnoSub extends Anno{
/**
* 重写父类方法
*/
@Override
public void feed(){
System.out.println("喂养乌龟");
}
/**
* 洗
*/
public void wash(){
System.out.println("给兔子洗澡...");
}
}
测试类被代理对象类型修改为:AnnoSub ,测试效果
这是因为当前注解无法被继承,为注解添加:@Inherited,则其可以被继承,子类能正常切入
package com.demo.moon.anno;
import java.lang.annotation.*;
/**
* @author
* @date 2022-10-03 19:57
* @since 1.8
*/
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface RabbitAnnotation {
}
子类切入效果
7.@target
注解类型,匹配带有指定类型注解的被代理类内的方法,注意代理类本身有指定注解,或者被代理类父类有指定的类型的且可继承的注解
切面类
package com.demo.moon.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
/**
* @author
* @date 2022-10-03 20:17
* @since 1.8
*/
@Aspect
public class AtTargetAspect {
@Pointcut("@target(com.demo.moon.anno.RabbitAnnotation)")
public void point(){}
@Before(value = "point()")
public void before(JoinPoint joinPoint) {
System.out.println("准备 ...");
}
}
测试类
package com.demo.moon;
import com.demo.moon.aspect.AtTargetAspect;
import com.demo.moon.cut.AnnoSub;
import org.springframework.aop.aspectj.annotation.AspectJProxyFactory;
/**
* @author
* @date 2022-10-03 17:51
* @since 1.8
*/
public class CutPointTest {
public static void main(String[] args) {
atTarget();
}
public static void atTarget(){
//创建被代理类
AnnoSub target = new AnnoSub();
//创建 AspectJProxyFactory
AspectJProxyFactory proxyFactory = new AspectJProxyFactory();
//设置被代理的目标对象
proxyFactory.setTarget(target);
//设置标注了 @Aspect 注解的类
proxyFactory.addAspect(AtTargetAspect.class);
//生成代理对象
AnnoSub proxy = proxyFactory.getProxy();
//调用
proxy.feed();
proxy.wash();
}
}
测试效果同上
8.@args
注解类型,方法参数类型的类上有指定注接,不是参数注接,是类型 类
定义一个带有指定注解的对象
package com.demo.moon.entity;
import com.demo.moon.anno.RabbitAnnotation;
/**
* @author
* @date 2022-10-03 20:23
* @since 1.8
*/
@RabbitAnnotation
public class RabbitEntity {
private String name;
public RabbitEntity(){
this.name = "兔子";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
切面类
package com.demo.moon.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
/**
* @author
* @date 2022-10-03 20:27
* @since 1.8
*/
@Aspect
public class AtArgsAspect {
@Pointcut("@args(*,com.demo.moon.anno.RabbitAnnotation)")
public void point(){}
@Before(value = "point()")
public void before(JoinPoint joinPoint) {
System.out.println("准备 ...");
}
}
被代理类
package com.demo.moon.cut;
import com.demo.moon.entity.RabbitEntity;
/**
* @author
* @date 2022-10-03 20:25
* @since 1.8
*/
public class ArgsAnno {
/**
* 洗
* @param rabbit
*/
public void wash(RabbitEntity rabbit){
System.out.println(String.format("给 %s 洗澡...",rabbit.getName()));
}
/**
* 喂养
* @param who
* @param rabbit
*/
public void feed(String who, RabbitEntity rabbit){
System.out.println(String.format("%s 喂食了 %s ...",who,rabbit.getName()));
}
/**
* 喂养
* @param who
* @param animal
*/
public void feed(String who,String animal){
System.out.println(String.format("%s 喂食了 %s ...",who,animal));
}
}
测试类
package com.demo.moon;
import com.demo.moon.aspect.AtTargetAspect;
import com.demo.moon.cut.ArgsAnno;
import com.demo.moon.entity.RabbitEntity;
import org.springframework.aop.aspectj.annotation.AspectJProxyFactory;
/**
* @author
* @date 2022-10-03 17:51
* @since 1.8
*/
public class CutPointTest {
public static void main(String[] args) {
atArgs();
}
public static void atArgs(){
//创建被代理类
ArgsAnno target = new ArgsAnno();
//创建 AspectJProxyFactory
AspectJProxyFactory proxyFactory = new AspectJProxyFactory();
//设置被代理的目标对象
proxyFactory.setTarget(target);
//设置标注了 @Aspect 注解的类
proxyFactory.addAspect(AtArgsAspect.class);
//生成代理对象
ArgsAnno proxy = proxyFactory.getProxy();
//参数对象
RabbitEntity rabbit = new RabbitEntity();
//调用
proxy.wash(rabbit);
proxy.feed("moon_one",rabbit);
proxy.feed("moon_two","兔子");
}
}
测试效果
9.@annotation
注解类型,被调用的方法上有指定注解
方法注解(不涉及能否继承)
package com.demo.moon.anno;
import java.lang.annotation.*;
/**
* @author
* @date 2022-10-03 20:41
* @since 1.8
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MethodAnnotation {
}
切面类
package com.demo.moon.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
/**
* @author
* @date 2022-10-03 20:39
* @since 1.8
*/
@Aspect
public class AtAnnotationAspect {
@Pointcut("@annotation(com.demo.moon.anno.MethodAnnotation)")
public void point(){}
@Before(value = "point()")
public void before(JoinPoint joinPoint) {
System.out.println("准备 ...");
}
}
被代理类父类
package com.demo.moon.cut;
import com.demo.moon.anno.MethodAnnotation;
/**
* @author
* @date 2022-10-03 20:36
* @since 1.8
*/
public class MethodAnno {
/**
* 喂养
*/
@MethodAnnotation
public void feed(){
System.out.println("喂养兔子...");
}
/**
* 洗
*/
@MethodAnnotation
public void wash(){
System.out.println("给兔子洗澡...");
}
}
被代理类子类
package com.demo.moon.cut;
import com.demo.moon.anno.MethodAnnotation;
/**
* @author
* @date 2022-10-03 20:37
* @since 1.8
*/
public class MethodAnnoSub extends MethodAnno{
/**
* 喂养
*/
@Override
public void feed(){
System.out.println("喂养乌龟...");
}
/**
* 训练
*/
@MethodAnnotation
public void train(){
System.out.println("训练乌龟...");
}
}
测试类
package com.demo.moon;
import com.demo.moon.aspect.AtAnnotationAspect;
import com.demo.moon.cut.MethodAnnoSub;
import org.springframework.aop.aspectj.annotation.AspectJProxyFactory;
/**
* @author
* @date 2022-10-03 17:51
* @since 1.8
*/
public class CutPointTest {
public static void main(String[] args) {
atAnno();
}
public static void atAnno(){
//创建被代理类
MethodAnnoSub target = new MethodAnnoSub();
//创建 AspectJProxyFactory
AspectJProxyFactory proxyFactory = new AspectJProxyFactory();
//设置被代理的目标对象
proxyFactory.setTarget(target);
//设置标注了 @Aspect 注解的类
proxyFactory.addAspect(AtAnnotationAspect.class);
//生成代理对象
MethodAnnoSub proxy = proxyFactory.getProxy();
//参数对象
//调用
proxy.feed();
proxy.wash();
proxy.train();
}
}
测试效果
被代理类,如果重写了父类方法,且不添加方法注解,则会导致父类原本带有注解的方法无法切入
10.bean
Bean,匹配指定名称的 Bean
定义一个测试用的Bean对象类
package com.demo.moon.cut;
/**
* @author
* @date 2022-10-03 20:54
* @since 1.8
*/
public class BeanName {
private String name;
public BeanName(String name){
this.name = name;
}
public String getName() {
System.out.println(String.format("%s 对象",name));
return name;
}
public void setName(String name) {
this.name = name;
}
}
切面类
package com.demo.moon.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
/**
* @author
* @date 2022-10-03 20:53
* @since 1.8
*/
@Aspect
public class BeanAspect {
@Pointcut("bean(rabbit)")
public void point(){}
@Before(value = "point()")
public void before(JoinPoint joinPoint) {
System.out.println("准备 ...");
}
}
Spring 初始化容器类
package com.demo.moon;
import com.demo.moon.aspect.BeanAspect;
import com.demo.moon.cut.BeanName;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
/**
* EnableAspectJAutoProxy 自动为符合条件 Bean 创建代理对象
*
* @author
* @date 2022-10-03 20:57
* @since 1.8
*/
@Configuration
@EnableAspectJAutoProxy
public class SpringBeanApp {
/**
* 创建代理类对象
* @return
*/
@Bean
public BeanAspect beanAspect(){
return new BeanAspect();
}
/**
* 创建兔子对象
* @return
*/
@Bean("rabbit")
public BeanName getBeanNameRabbit(){
return new BeanName("rabbit");
}
/**
* 创建乌龟对象
* @return
*/
@Bean("tortoise")
public BeanName getBeanNameTortoise(){
return new BeanName("tortoise");
}
}
测试类
package com.demo.moon;
import com.demo.moon.cut.BeanName;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @author
* @date 2022-10-03 17:51
* @since 1.8
*/
public class CutPointTest {
public static void main(String[] args) {
bean();
}
public static void bean(){
//基于 Java 配置文件初始化实例,另一种高级容器为 ClassPathXmlApplicationContext 基于classpath下的xml配置文件
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringBeanApp.class);
//从容器中获取 rabbit
BeanName rabbit = context.getBean("rabbit", BeanName.class);
rabbit.getName();
//从容器中获取 tortoise
BeanName tortoise = context.getBean("tortoise", BeanName.class);
tortoise.getName();
}
}
测试效果
11.引用切点
将切入点定义放在同一个类里统一管理,切面类的切点直接引用已定义的切点
切点管理类
package com.demo.moon.aspect;
import org.aspectj.lang.annotation.Pointcut;
/**
* @author
* @date 2022-10-03 21:12
* @since 1.8
*/
public class CunPointManagement {
@Pointcut("target(com.demo.moon.cut.Sub)")
public void targetPoint(){}
@Pointcut("args(String)")
public void argsPoint(){}
}
切面类(引用已有切点)
package com.demo.moon.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
/**
* @author
* @date 2022-10-03 21:15
* @since 1.8
*/
@Aspect
public class ReferenceAspect {
@Pointcut("com.demo.moon.aspect.CunPointManagement.targetPoint()")
public void beforePoint(){}
@Pointcut("com.demo.moon.aspect.CunPointManagement.argsPoint()")
public void afterPoint(){}
/**
* 针对切入点做前置增强
* @param joinPoint
*/
@Before(value = "beforePoint()")
public void before(JoinPoint joinPoint) {
System.out.println("准备...");
}
/**
* 针对切入点做前置增强
* @param joinPoint
*/
@After(value = "afterPoint()")
public void after(JoinPoint joinPoint) {
System.out.println("打扫卫生...");
}
}
测试类
package com.demo.moon;
import com.demo.moon.aspect.ReferenceAspect;
import com.demo.moon.cut.Sub;
import org.springframework.aop.aspectj.annotation.AspectJProxyFactory;
/**
* @author
* @date 2022-10-03 17:51
* @since 1.8
*/
public class CutPointTest {
public static void main(String[] args) {
bean();
}
public static void bean(){
//创建被代理类
Sub target = new Sub();
//创建 AspectJProxyFactory
AspectJProxyFactory proxyFactory = new AspectJProxyFactory();
//设置被代理的目标对象
proxyFactory.setTarget(target);
//设置标注了 @Aspect 注解的类
proxyFactory.addAspect(ReferenceAspect.class);
//生成代理对象
Sub proxy = proxyFactory.getProxy();
//调用
proxy.feed("兔子");
}
}
测试效果
12.组合切点
Pointcut 定义时,还可以使用运算符
运算符 | 说明 |
---|---|
&& | (与)多个匹配都需要满足 |
|| | (或)多个匹配中只需满足一个 |
! | (非)匹配不满足的情况下 |