spring aop原理


概念

摘自:百度百科
在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

动态代理

代理模式:为其他对象提供一种代理以控制对这个对象的访问,增强一个类中的某个方法,对程序进行扩展

jdk动态代理

需要实现接口

public interface UserInterface {

    void test();

    void run();
}

public class UserService implements UserInterface {

    @Override
    public void test(){
        System.out.println("test");
    }

    @Override
    public void run() {
        System.out.println("run");
    }
}

public class UserInterfaceInvocationHandler implements InvocationHandler {

    private UserInterface userInterface;

    public UserInterfaceInvocationHandler(UserInterface userInterface){
        this.userInterface = userInterface;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before");
        Object value = method.invoke(userInterface, args);
        System.out.println("after");
        return value;
    }
}

public class JdkProxyTest {

    public static void main(String[] args) {
        UserInterface userInterfaceBase = new UserService();
        UserInterfaceInvocationHandler userInterfaceInvocationHandler = new UserInterfaceInvocationHandler(userInterfaceBase);
        UserInterface userInterface = (UserInterface) Proxy.newProxyInstance(JdkProxyTest.class.getClassLoader(), new Class[]{UserInterface.class}, userInterfaceInvocationHandler);
        userInterface.test();
    }
}

cglib动态代理

public class CgLibProxyTest {

    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(UserService.class);
        enhancer.setCallbacks(new Callback[]{
                (MethodInterceptor) (obj, method, args1, proxy) -> {
                    System.out.println("before");
                    Object value = proxy.invokeSuper(obj, args1);
                    System.out.println("after");
                    return value;
                }, NoOp.INSTANCE
        });
        //cjlib callback 过滤
        enhancer.setCallbackFilter(method -> {
            //test方法使用第一个callback,其他方法使用第二个callback
            if("test".equals(method.getName())){
                return 0;
            }
            return 1;
        });
        UserService userService = (UserService)enhancer.create();
        userService.test();
        System.out.println("--------------------------------------");
        userService.run();
    }
}

示例

https://gitee.com/luoye/examples/tree/main/aop/simpleAop

Spring AOP

ProxyFactory

在Spring中对代理进行了封装,封装后的类叫:ProxyFactory,使用方法如下:

public class SimpleProxyFactoryTest {

    public static void main(String[] args) {
        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.setTarget(new UserService());
        proxyFactory.addAdvice((MethodInterceptor) invocation -> {
            System.out.println("before");
            Object value = invocation.proceed();
            System.out.println("after");
            return value;
        });

        UserService userService = (UserService) proxyFactory.getProxy();
        userService.test();
    }
}

通过使用ProxyFactory我们不用再关心到底使用cjlib换算jdk动态代理了,ProxyFactory会自己判断。

Advice分类

类型 说明
Before Advice 方法执行之前执行
After Returning Advice 方法执行之后执行
After Throwing Advice 方法抛出异常后执行
After (Finally) Advice 方法执行完finally之后执行,比return更往后
Around Advice 可以自定义执行顺序
/**
 * 方法执行之后执行
 *
 * @author lmm
 * @date 2022-03-23
 */
public class CustomAfterReturningAdvice implements AfterReturningAdvice {
    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("after returning");
    }
}

/**
 * 抛出异常之后执行
 *
 * @author lmm
 * @date 2022-03-23
 */
public class CustomAfterThrowingAdvice implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        try{
            return invocation.proceed();
        }catch (Exception e){
            System.out.println("after throwing msg: "+e.getMessage());
            return null;
        }
    }
}

/**
 * 方法执行前、后执行
 *
 * @author lmm
 * @date 2022-03-23
 */
public class CustomAroundAdvice implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        System.out.println("around before");
        Object value = invocation.proceed();
        System.out.println("around after");
        return value;
    }
}

/**
 * 方法执行之前执行
 *
 * @author lmm
 * @date 2022-03-23
 */
public class CustomBeforeAdvice implements MethodBeforeAdvice {
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("before");
    }
}

/**
 * 测试advice
 * 
 * @author lmm
 * @date 2022-03-23
 */
public class AdviceProxyFactoryTest {

    public static void main(String[] args) {
        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.setTarget(new UserService());
        proxyFactory.addAdvice(new CustomAroundAdvice());
        proxyFactory.addAdvice(new CustomBeforeAdvice());
        proxyFactory.addAdvice(new CustomAfterReturningAdvice());
        proxyFactory.addAdvice(new CustomAfterThrowingAdvice());
        UserService userService = (UserService) proxyFactory.getProxy();
        userService.test();
        System.out.println("-----------------------");
        userService.testThrowing();
    }
}

Advisor

一个Advicsor是由一个Pointcut和一个Advice组成的,通过Pointcut可以指定需要被代理的逻辑

/**
 * 简单测试Advisor
 *
 * @author lmm
 * @date 2022-03-23
 */
public class SimpleAdvisorTest {

    public static void main(String[] args) {
        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.setTarget(new UserService());
        proxyFactory.addAdvisor(new PointcutAdvisor() {
            @Override
            public Pointcut getPointcut() {
                return new StaticMethodMatcherPointcut() {
                    @Override
                    public boolean matches(Method method, Class<?> targetClass) {
                        return "test".equals(method.getName());
                    }
                };
            }

            @Override
            public Advice getAdvice() {
                return new MethodInterceptor() {
                    @Override
                    public Object invoke(MethodInvocation invocation) throws Throwable {
                        System.out.println("before");
                        return invocation.proceed();
                    }
                };
            }

            @Override
            public boolean isPerInstance() {
                return false;
            }
        });

        UserService userService = (UserService) proxyFactory.getProxy();
        userService.test();
        System.out.println("------------------");
        userService.run();
    }
}

ProxyFactory示例

https://gitee.com/luoye/examples/tree/main/aop/proxyFactoryTest

ProxyFactoryBean

Spring创建一个AOP代理的基本方法是使用ProxyFactoryBean,它提供了切点和增强的控制能力,常用配置如下

属性名称 说明
target 代理的目标对象
proxyInterfaces 代理要实现的接口
interceptorNames 植入目标的Advice
singleton 返回的代理是否为单例,默认:true
optimize 是否优化,设置为true是,强制使用cglib

使用示例

/**
 * 用户service
 *
 * @author lmm
 * @date 2022-03-23
 */
public class UserService {

    public void test(){
        System.out.println("test");
    }
}

/**
 * ProxyFactoryBean配置
 *
 * @author lmm
 * @date 2022-03-23
 */
@Configuration
public class ProxyFactoryBeanConfig {

    /**
     * 方法执行前执行
     * @return
     */
    @Bean
    public MethodInterceptor beforeAdvice(){
        return new MethodInterceptor() {
            @Override
            public Object invoke(MethodInvocation invocation) throws Throwable {
                System.out.println("before");
                return invocation.proceed();
            }
        };
    }

    /**
     * 用户service代理对象
     * @return
     */
    @Bean
    public ProxyFactoryBean userServiceProxy(){
        UserService userService = new UserService();
        ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
        proxyFactoryBean.setTarget(userService);
        proxyFactoryBean.addAdvice(new MethodInterceptor() {
            @Override
            public Object invoke(MethodInvocation invocation) throws Throwable {
                Object value = invocation.proceed();
                System.out.println("after");
                return value;
            }
        });
        proxyFactoryBean.setInterceptorNames("beforeAdvice");
        return proxyFactoryBean;
    }
}

/**
 * ProxyFactoryBean测试
 *
 * @author lmm
 * @date 2022-03-23
 */
public class ProxyFactoryBeanTest {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ProxyFactoryBeanConfig.class);
        UserService userService = context.getBean("userServiceProxy",UserService.class);
        userService.test();
    }
}

BeanNameAutoProxyCreator

通过指定bean的名字,来对该bean进行代理

示例:

/**
 * 用户service
 *
 * @author lmm
 * @date 2022-03-23
 */
@Component
public class UserService {

    public void test(){
        System.out.println("test");
    }
}

/**
 * bean名称代理配置
 *
 * @author lmm
 * @date 2022-03-23
 */
@Configuration
@ComponentScan("show.lmm.demo.beanNameAutoProxy")
public class BeanNameAutoProxyConfig {

    /**
     * 方法执行前执行
     * @return
     */
    @Bean
    public MethodInterceptor beforeAdvice(){
        return new MethodInterceptor() {
            @Override
            public Object invoke(MethodInvocation invocation) throws Throwable {
                System.out.println("before");
                return invocation.proceed();
            }
        };
    }

    @Bean
    public BeanNameAutoProxyCreator beanNameAutoProxyCreator(){
        BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator();
        beanNameAutoProxyCreator.setBeanNames("user*");
        beanNameAutoProxyCreator.setInterceptorNames("beforeAdvice");
        return beanNameAutoProxyCreator;
    }
}

/**
 * bean名称代理测试
 *
 * @author lmm
 * @date 2022-03-23
 */
public class BeanNameAutoProxyTest {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanNameAutoProxyConfig.class);
        UserService userService = context.getBean("userService",UserService.class);
        userService.test();
    }
}

DefaultAdvisorAutoProxyCreator

DefaultAdvisorAutoProxyCreator会直接查找所有Advisor类型的Bean,根据Advisor中的Pointcut和Advice信息,确定要代理的Bean以及代理的逻辑。

示例:

/**
 * 用户service
 *
 * @author lmm
 * @date 2022-03-23
 */
@Component
public class UserService {

    public void test(){
        System.out.println("test");
    }

    public void run(){
        System.out.println("run");
    }
}

/**
 * 默认Advisor自动代理配置
 *
 * @author lmm
 * @date 2022-03-23
 */
@Configuration
@ComponentScan("show.lmm.demo.defaultAdvisorAutoProxy")
public class DefaultAdvisorAutoProxyConfig {

    /**
     * 默认切点advisor
     *
     * @return
     */
    @Bean
    public DefaultPointcutAdvisor defaultPointcutAdvisor() {
        NameMatchMethodPointcut nameMatchMethodPointcut = new NameMatchMethodPointcut();
        nameMatchMethodPointcut.addMethodName("test");

        DefaultPointcutAdvisor defaultPointcutAdvisor = new DefaultPointcutAdvisor();
        defaultPointcutAdvisor.setPointcut(nameMatchMethodPointcut);
        defaultPointcutAdvisor.setAdvice(new MethodInterceptor() {
            @Override
            public Object invoke(MethodInvocation invocation) throws Throwable {
                System.out.println("before");
                return invocation.proceed();
            }
        });
        return defaultPointcutAdvisor;
    }

    /**
     * 默认Advisor自动代理
     *
     * @return
     */
    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        return new DefaultAdvisorAutoProxyCreator();
    }
}

/**
 * 默认Advisor自动代理测试
 *
 * @author lmm
 * @date 2022-03-23
 */
public class DefaultAdvisorAutoProxyTest {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(DefaultAdvisorAutoProxyConfig.class);
        UserService userService = context.getBean("userService", UserService.class);
        userService.test();
        System.out.println("------------------------");
        userService.run();
    }
}

注解方式使用aop

概念

  1. Aspect:切面,可以在切面中定义Pointcut、Advice等。
  2. Join point:连接点,表示一个程序在执行过程中的一个点,在Spring aop中,一个连接点通常表示一个方法的直销。
  3. Advice:通知,表示在特定连接点上采取的动作。在Spring aop中,会用Interceptor拦截器来实现Advice,并且在连接点周围维护一个Interceptor链。
  4. Pointcut:切点,用来匹配一个或多个连接点,Advice与切点表达式是关联着一起的,Advice将会执行在和切点表达式所匹配的连接点上。
  5. Introduction:可以使用@DeclareParents来给所匹配的类增加一个接口,并指定一个默认实现。
  6. Target object:目标对象,被代理对象。
  7. Aop proxy:表示代理工作,在spring中,要么用jdk动态代理,要么用cglib代理。
  8. Weaving:织入,表示创建代理对象的动作,可以发生在编译期(Aspejctj),或运行时(spring aop)

spring aop 注解

注解 说明
@Aspect 定义切面
@Pointcut 定义切点
@Before 方法执行前,执行aop逻辑
@Around 方法执行前/后,执行aop逻辑
@After 方法执行后,执行aop逻辑
@AfterReturning 方法返回前(finally),执行aop逻辑
@AfterThrowing 方法执行异常时,执行aop逻辑

示例:
build.gradle 中引入依赖

dependencies {
    // https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-aop
    implementation group: 'org.springframework.boot', name: 'spring-boot-starter-aop', version: '2.6.4'
}
/**
 * 用户service
 *
 * @author lmm
 * @date 2022-03-23
 */
@Component
public class UserService {

    public void test(){
        System.out.println("test");
    }

    public void run(){
        System.out.println("run");
    }
}

/**
 * 自定义aop逻辑
 *
 * @author lmm
 * @date 2022-03-23
 */
@Aspect
@Component
public class CustomAspect {

    @Before("execution(public void show.lmm.demo.springAop.UserService.test())")
    public void before(JoinPoint joinPoint){
        System.out.println("before");
    }
}

/**
 * spring aop测试
 */
@SpringBootApplication
public class SpringAopTest {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(SpringAopTest.class, args);
        UserService userService = context.getBean("userService", UserService.class);
        userService.test();
        System.out.println("------------------------");
        userService.run();
    }
}

TargetSource

在Spring AOP中,被代理对象就是bean对象,是由BeanFactory创建出来的。Spring AOP中还提供了TargetSource机制,可以自定义逻辑来创建被代理对象。

示例:

/**
 * 用户service
 *
 * @author lmm
 * @date 2022-03-23
 */
@Component
public class UserService {

    private String userName;

    public UserService(String userName){
        this.userName = userName;
    }

    public void test(){
        System.out.println("test "+userName);
    }
}

/**
 * 被代理对象config
 *
 * @author lmm
 * @date 2022-03-23
 */
@Configuration
public class TargetSourceConfig {

    @Bean
    public UserService userService(){
        TargetSource targetSource = new TargetSource() {
            @Override
            public Class<?> getTargetClass() {
                return UserService.class;
            }

            @Override
            public boolean isStatic() {
                return false;
            }

            @Override
            public Object getTarget() throws Exception {
                return new UserService("张三");
            }

            @Override
            public void releaseTarget(Object target) throws Exception {
                //对象池需要处理
            }
        };

        ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
        proxyFactoryBean.setTargetSource(targetSource);
        return (UserService) proxyFactoryBean.getObject();
    }
}

/**
 * 测试TargetSource
 *
 * @author lmm
 * @date 2022-03-23
 */
public class TargetSourceTest {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(TargetSourceConfig.class);
        UserService userService = context.getBean("userService", UserService.class);
        userService.test();
    }
}

Introduction

用于将已有的类引入新的接口,并提供新的服务

示例:

/**
 * Service
 *
 * @author lmm
 * @date 2022-03-23
 */
public interface Service {
    void test();
}

/**
 * 用户service
 *
 * @author lmm
 * @date 2022-03-23
 */
@Component
public class UserService implements Service{

    @Override
    public void test(){
        System.out.println("test");
    }
}

/**
 * 扩展接口
 *
 * @author lmm
 * @date 2022-03-23
 */
public interface ExtendInterface {

    void run();
}

/**
 * 扩展实现
 *
 * @author lmm
 * @date 2022-03-23
 */
public class ExtendImpl implements ExtendInterface {
    @Override
    public void run() {
        System.out.println("run");
    }
}

/**
 * 自定义切面
 *
 * @author lmm
 * @date 2022-03-23
 */
@Aspect
@Component
public class CustomAspect {

    @DeclareParents(value = "show.lmm.demo.introduction.UserService",defaultImpl = ExtendImpl.class)
    public ExtendInterface extendService;
}

/**
 * 测试Introduction
 *
 * @author lmm
 * @date 2022-03-23
 */
@SpringBootApplication
public class IntroductionTest {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(IntroductionTest.class, args);
        ExtendInterface extendInterface = context.getBean("userService", ExtendInterface.class);
        UserService userService = context.getBean("userService", UserService.class);
        extendInterface.run();
        userService.test();
    }
}

Spring AOP示例

https://gitee.com/luoye/examples/tree/main/aop/springAopDemo


文章作者: Ming Ming Liu
文章链接: https://www.lmm.show/19/
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Ming Ming Liu !
  目录