Spring AOP实现浅析一

动态代理就是,在程序运行期,创建目标对象的代理对象,并对目标对象中的方法进行功能性增强的一种技术。

一 Cglib

Cglib是一个开源项目,它的底层是字节码处理框架ASM,提供了比jdk更为强大的动态代理。相比于jdk动态代理的优势有:

  • jdk动态代理只能基于接口,代理对象只能是接口类型,而Cglib通过生成子类来实现的,代理对象既可以是实现类,又可以是接口。
  • Cglib速度比jdk动态代理更快,性能更好。

Spring对Cglib做了封装,提供了spring-cglib-repack.jar包。

java 复制代码
public class UserService {
    public void test() {
        System.out.println("执行UserService.test");
    }
java 复制代码
import com.xiakexing.service.UserService;
import java.lang.reflect.Method;
import org.springframework.cglib.proxy.Callback;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

public class UserServiceProxy {

    public static void main(String[] args) {
        UserService target = new UserService();
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(UserService.class);
        // 定义代理逻辑
        enhancer.setCallbacks(new Callback[]{new MethodInterceptor() {
            @Override
            public Object intercept(Object proxy, Method method, Object[] params, MethodProxy
                                    methodProxy) throws Throwable {
                System.out.println("before...");
                Object result = methodProxy.invoke(target, params);
                System.out.println("after...");
                return result;
            }
        }});
        // 创建代理对象
        UserService userService = (UserService) enhancer.create();
        userService.test();
    }
}

二 JDK动态代理

大家或多或少都有了解,此处不在赘述。

三 ProxyFactory类

对上述两种代理实现,Spring进行了封装,统一为ProxyFactory,表示创建代理对象的一个工厂。

我们不用关心底层使用了cglib还是JDK动态代理,ProxyFactory会自动判断:

  • 如果被代理类实现了接口,就会用jdk动态代理;
  • 如果没有实现接口,就会用cglib技术。

3.1 使用Cglib

java 复制代码
package com.xiakexing.aop;

import com.xiakexing.service.UserService;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.framework.ProxyFactory;

public class ProxyFactoryTest {

    public static void main(String[] args) {
        UserService target = new UserService();
        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.setTarget(target);
        proxyFactory.addAdvice(new MethodInterceptor() {
            @Override
            public Object invoke(MethodInvocation invocation) throws Throwable {
                System.out.println("before...");
                Object result = invocation.proceed();
                System.out.println("after...");
                return result;
            }
        });
        UserService userService = (UserService) proxyFactory.getProxy();
        userService.test();
    }
}

上面示例中,没有给UserService指定接口实现, 因此使用了Cglib代理。

3.2 使用JDK代理

定义OrderInterface接口,提供实现类OrderService。

java 复制代码
public interface OrderInterface {
    void test();
}
java 复制代码
public class OrderService implements OrderInterface {

    public void test() {
        System.out.println("执行OrderService.test");
    }
}
java 复制代码
package com.xiakexing.aop;

import com.xiakexing.service.OrderInterface;
import com.xiakexing.service.OrderService;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.framework.ProxyFactory;

public class ProxyFactoryTest {

    public static void main(String[] args) {
        OrderInterface target = new OrderService();
        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.setTarget(target);
        // 添加要实现的接口
        proxyFactory.addInterface(OrderInterface.class);
        proxyFactory.addAdvice(new MethodInterceptor() {
            @Override
            public Object invoke(MethodInvocation invocation) throws Throwable {
                System.out.println("before...");
                Object result = invocation.proceed();
                System.out.println("after...");
                return result;
            }
        });
        OrderInterface orderService = (OrderInterface) proxyFactory.getProxy();
        System.out.println(orderService.getClass().getName());
        orderService.test();
    }
}

当主动指定代理对象要实现OrderInterface接口时,将使用JDK动态代理。

四 ProxyFactoryBean类

我们希望能够从Spring容器中,直接获取ProxyFactory所创建的代理对象,就要使用ProxyFactoryBean。

该类实现了FactoryBean接口,用于创建Proxy对象,需要提供被代理类和代理逻辑,getObject()会返回代理类Bean对象。

java 复制代码
// 返回UserService的代理对象
@Bean
public ProxyFactoryBean userServiceProxy() {
    UserService userService = new UserService();
    ProxyFactoryBean factoryBean = new ProxyFactoryBean();
    factoryBean.setTarget(userService);
    factoryBean.addAdvice(new MethodInterceptor() {
        @Override
        public Object invoke(MethodInvocation invocation) throws Throwable {
            System.out.println("before...");
            Object result = invocation.proceed();
            System.out.println("after...");
            return result;
        }
    });
    return factoryBean;
}

五 一些概念

5.1 Advice通知

在已有方法的前、后、异常或最终处加入的增加逻辑,包括:

  1. Before Advice:方法之前执行
  2. After returning advice:方法return后执行
  3. After throwing advice:方法抛异常后执行
  4. After finally advice:方法执行完finally之后执行,在return之后
  5. Around advice:这是功能最强大的Advice,可以自定义执行顺序

5.2 Pointcut切面点

需要应用Advice的方法范围,指定对哪些类的哪些方法进行增强。

5.3 Advisor接口

一个Advisor由一个Pointcut和一个Advice组成。子类PointcutAdvisor有如下方法。

如下,创建UserService的代理对象,只对名称为test的方法进行增强。

java 复制代码
UserService target = new UserService();
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(target);
proxyFactory.addAdvisor(new PointcutAdvisor() {
    @Override
    public Pointcut getPointcut() {
        return new StaticMethodMatcherPointcut() {
            @Override
            public boolean matches(Method method, Class<?> targetClass) {
                return method.getName().equals("test");
            }
        };
    }

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

    @Override
    public boolean isPerInstance() {
        return false;
    }
});
UserService userService = (UserService) proxyFactory.getProxy();
userService.test();

六 使用注解

上面示例中,我们自行指定了要代理的类,自行创建了Advisor对象。Spring中代理肯定不能如此麻烦的实现。

使用注解,将Advice、Pointcut都定义为Bean放入容器中,Spring就具备了动态生成代理对象的能力了。

java 复制代码
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class SimpleAspect {

    @Before("execution(public void com.xiakexing.service.UserService.test())")
    public void before(JoinPoint joinPoint) {
        System.out.println("Before...");
    }
}

OOP表示面向对象编程,AOP表示面向切面编程,都只是一种编程思想。而Spring提供了一套机制,可以让我们更加容易的实现AOP编程,这套机制我们称之为 Spring AOP

通过注解方式来定义Pointcut和Advice,首创是AspectJ组件。Spring依赖了AspectJ,会去解析相应注解,利用动态代理机制生成代理对象

相关推荐
XYu1230120 分钟前
Spring Boot 热部署实现指南
java·ide·spring boot·intellij-idea
yang_shengy2 小时前
【JavaEE】Spring(5):Mybatis(上)
spring·java-ee·mybatis
程序猿零零漆2 小时前
SpringCloud系列教程:微服务的未来(十九)请求限流、线程隔离、Fallback、服务熔断
java·spring cloud·微服务
pianmian12 小时前
使用where子句筛选记录
java·服务器·数据库
Allen Bright4 小时前
Java动态代理:原理与实现
java·开发语言
假客套5 小时前
Java小白入门教程:两大类型的修饰符以及示例
java·开发语言
细心的莽夫6 小时前
SpringBoot 基础(Spring)
spring boot·后端·spring
怒码ing7 小时前
【已解决】redisCache注解失效,没写cacheConfig
java·开发语言·数据库
何似在人间5757 小时前
Java的Integer缓存池
java·开发语言·缓存