Java Dynamic Proxy And Aspect Application (二)


前面已经简单介绍了 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用于匹配当前执行的方法传入的参数为指定类型的执行方法
beanSpring 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 表示配置的类)
withintargettarget.getClass.equals(exp.class)
thisproxyexp.class.isAssignableFrom(proxy.getClass())
targettargetexp.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 定义时,还可以使用运算符

运算符说明
&&(与)多个匹配都需要满足
||(或)多个匹配中只需满足一个
!(非)匹配不满足的情况下
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猪悟道

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值