Spring: Spring AOP 方面/切面(Aspect)

1.美图

在这里插入图片描述

2.概述

概念参考:Spring :Spring AOP 中的一些术语

由于增强包括横切代码,又包含部分连接点信息(方法前、方法后主方位信息),所以可以仅通过增强类生成一个切面。 但切点仅仅代表目标类连接点的部分信息(类和方法的定位),所以仅有切点无法制作出一个切面,必须结合增强才能制作出切面。Spring使用org.springframework.aop.Advisor接口标识切面概念,一个切面同时包含横切代码和连接点信息。

3.切面分类

切面可以分为3类:一般切面、切点切面、引介切面

3.1 一般切面Advisor

org.springframework.aop.Advisor代表一般切面,仅包含一个Advice ,因为Advice包含了横切代码和连接点信息,所以Advice本身一个简单的切面,只不过它代表的横切的连接点是所有目标类的所有方法,因为这个横切面太宽泛,所以一般不会直接使用

3.2 切点切面PointcutAdvisor

org.springframework.aop.PointcutAdvisor ,代表具有切点的切面,包括AdvicePointcut两个类,这样就可以通过类、方法名以及方位等信息灵活的定义切面的连接点,提供更具实用性的切面。PointcutAdvisor主要有6个具体的实现类:

  1. DefaultPointcutAdvisor:最常用的切面类型,它可以通过任意Pointcut和Advice定义一个切面,唯一不支持的就是引介的切面类型,一般可以通过扩展该类实现自定义的切面
  2. NameMatchMethodPointcutAdvisor:通过该类可以定义按方法名定义切点的切面
  3. AspectJExpressionPointcutAdvisor:用于AspectJ切点表达式定义切点的切面
  4. StaticMethodMatcherPointcutAdvisor:静态方法匹配器切点定义的切面,默认情况下匹配所有的的目标类
  5. AspectJPointcutAdvisor:用于AspectJ语法定义切点的切面

3.3 引介切面IntroductionAdvisor

org.springframework.aop.IntroductionAdvisor代表引介切面, 引介切面是对应引介增强的特殊的切面,它应用于类层上面,所以引介切点使用ClassFilter进行定义。

切入点 通过ClassFilter可以定位到具体的类上,MethodMatcher可以定位到具体的方法上

4.案例

4.1 接口和实现类(目标对象)

package com.spring.boot.aop.acpect;

/**
 * Description:
 *
 * @author lcc
 * @version 1.0
 * @date 2020/1/14 11:13 下午
 */
public interface Animal {
    void sayHello();
}

package com.spring.boot.aop.acpect;

/**
 * Description:
 *
 * @author lcc
 * @version 1.0
 * @date 2020/1/14 11:14 下午
 */
public class Cat implements Animal {

    @Override
    public void sayHello() {
        System.out.println("我是Cat类的sayHello方法。。。");
    }

    public void sayHelloCat() {
        System.out.println("我是一只猫。。。");
    }

}

package com.spring.boot.aop.acpect;

/**
 * Description:
 *
 * @author lcc
 * @version 1.0
 * @date 2020/1/14 11:14 下午
 */
public class Dog implements Animal{

    @Override
    public void sayHello() {
        System.out.println("我是Dog类的sayHello方法。。。");
    }

    public void sayHelloDog() {
        System.out.println("我是一只狗。。。");
    }
}

增强(为了演示,这里只实现MethodBeforeAdvice前置增强接口)

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

/**
 * 前置增强
 * @author: LiYanChao
 * @create: 2018-11-01 21:50
 */
public class MyMethodBeforeAdvice implements MethodBeforeAdvice {
	@Override
	public void before(Method method, Object[] args, Object target) throws Throwable {
		System.out.println("==前置增强");
		System.out.println("==方法名:" + method.getName());
		if (null != args && args.length > 0) {`在这里插入代码片`
			for (int i = 0; i < args.length; i++) {
				System.out.println("==第" + (i + 1) + "参数:" + args[i]);
			}
		}
		System.out.println("==目标类信息:" + target.toString());
	}

}

切面

package com.spring.boot.aop.acpect;

import org.springframework.aop.ClassFilter;
import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor;

import java.lang.reflect.Method;

/**
 * Description:
 *  静态普通方法名匹配切面
 * @author lcc
 * @version 1.0
 * @date 2020/1/14 11:15 下午
 */
public class MyStaticPointcutAdvisor extends StaticMethodMatcherPointcutAdvisor {

    private static String METHOD_NAME = "sayHello";

    /**
     * 静态方法匹配判断,这里只有方法名为sayHello的,才能被匹配
     */
    @Override
    public boolean matches(Method method, Class<?> targetClass) {
        return METHOD_NAME.equals(method.getName());
    }

    /**
     * 覆盖getClassFilter,只匹配Dog类
     * @return
     */
    @Override
    public ClassFilter getClassFilter() {
        return new ClassFilter() {
            @Override
            public boolean matches(Class<?> clazz) {
                return Dog.class.isAssignableFrom(clazz);
            }
        };
    }
}

StaticMethodMatcherPointcutAdvisor抽象类继承了StaticMethodMatcherPointcut类并实现了PointcutAdvisor接口。在MyStaticPointcutAdvisor类中我们实现了matches静态方法匹配判断,并且只有方法名为sayHello的,才能被匹配;覆盖了getClassFilter方法,并且只匹配Dog类。

4.2 测试

package com.spring.boot.aop.acpect;

import com.spring.boot.aop.advice.beforeadvice.MyMethodBeforeAdvice;
import org.junit.Test;
import org.springframework.aop.framework.ProxyFactory;

import static org.junit.Assert.*;

public class MyStaticPointcutAdvisorTest {

    /**
     * 我是一只狗。。。
     *
     *
     *
     * ==前置增强
     * ==方法名:sayHello
     * ==目标类信息:com.spring.boot.aop.acpect.Dog@5c072e3f
     * 我是Dog类的sayHello方法。。。
     *
     * 结论:
     * 在代码里配置了,在类一级只匹配Dog类,在方法一级只匹配sayHello方法。运行结果与我们的设置符合。只有Dog类的sayHello被增强了。
     */
    @Test
    public void test1() {
        // 1、创建目标类、增强、切入点
        Animal animal = new Dog();
        MyMethodBeforeAdvice advice = new MyMethodBeforeAdvice();
        MyStaticPointcutAdvisor advisor = new MyStaticPointcutAdvisor();

        // 2、创建ProxyFactory并设置目标类、增强、切面
        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.setTarget(animal);
        // 为切面类提供增强
        advisor.setAdvice(advice);
        proxyFactory.addAdvisor(advisor);

        // 3、生成代理实例
        Dog proxyDog = (Dog) proxyFactory.getProxy();
        proxyDog.sayHelloDog();
        System.out.println("\n\n");
        proxyDog.sayHello();

    }


    /**
     * 我是一只猫。。。
     *
     *
     *
     * 我是Cat类的sayHello方法。。。
     *
     * 结论:
     * 没有一个方法被增强,虽然在Cat类中也有sayHello方法,但是我们设置的是只匹配Dog类,所以虽然在Cat类中有sayHello方法,但是它也是无法被增强的。
     */
    @Test
    public void test2() {
        // 1、创建目标类、增强、切入点
        Animal animal = new Cat();
        MyMethodBeforeAdvice advice = new MyMethodBeforeAdvice();
        MyStaticPointcutAdvisor advisor = new MyStaticPointcutAdvisor();

        // 2、创建ProxyFactory并设置目标类、增强、切面
        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.setTarget(animal);
        // 为切面类提供增强
        advisor.setAdvice(advice);
        proxyFactory.addAdvisor(advisor);

        // 3、生成代理实例
        Cat proxyDog = (Cat) proxyFactory.getProxy();
        proxyDog.sayHelloCat();
        System.out.println("\n\n");
        proxyDog.sayHello();

    }


}
发布了1050 篇原创文章 · 获赞 436 · 访问量 127万+

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 酷酷鲨 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览