从零开始造Spring09---实现AOP的JDK代理

简介: 接上一篇从零开始造Spring08—AOP(介绍以及实现ReflectiveMethodInvocation和AopProxyFactory),这篇文章我们接着来讲Spring的AOP的JDK代理,这是学习刘欣老师的《从零开始造Spring》的学习笔记。

前言

接上一篇从零开始造Spring08—AOP(介绍以及实现ReflectiveMethodInvocation和AopProxyFactory),这篇文章我们接着来讲Spring的AOP的JDK代理,这是学习刘欣老师的《从零开始造Spring》的学习笔记。

JDK代理的说明

与Cglib代理有所不同的是,JDK代理是针对接口的代理。所有要使用JDK代理必须要有接口。

测试类

public interface IPetStoreService {
    void placeOrder();
}
@Component(value = "petStoreService")
public class PetStoreService implements IPetStoreService {
    public PetStoreService() {
    }
    @Override
    public void placeOrder() {
        System.out.println("place order");
        MessageTracker.addMsg("place order");
    }
}

XML中的配置

<context:component-scan
        base-package="com.jay.spring.service.v6">
    </context:component-scan>
    <!--作为一个切面-->
    <bean id="tx" class="com.jay.spring.tx.TransactionManager" />
    <aop:config>
        <aop:aspect ref="tx">
            <!--切点-->
            <aop:pointcut id="placeOrder"
                expression="execution(* com.jay.spring.service.v6.*.placeOrder(..))" />
            <aop:after-throwing pointcut-ref="placeOrder" method = "rollback"/>
            <aop:after-returning pointcut-ref="placeOrder"
                method="commit" />
            <aop:before pointcut-ref="placeOrder" method="start" />         
        </aop:aspect>
    </aop:config>

JdkAopProxyFactory 类

public class JdkAopProxyFactory implements AopProxyFactory,InvocationHandler {
    private static final Log logger = LogFactory.getLog(JdkAopProxyFactory.class);
    private final AopConfig aopConfig;
    public JdkAopProxyFactory(AopConfig config) {
        Assert.notNull(config, "AdvisedSupport must not be null");
        if (config.getAdvices().size() == 0) {
            throw new AopConfigException("No advice specified");
        }
        this.aopConfig = config;
    }
    /**
     * 获取代理
     * @return
     */
    @Override
    public Object getProxy() {
        return getProxy(ClassUtils.getDefaultClassLoader());
    }
    @Override
    public Object getProxy(ClassLoader classLoader) {
        if (logger.isDebugEnabled()) {
            logger.debug("Creating JDK dynamic proxy: target source is " + this.aopConfig.getTargetObject());
        }
        Class<?>[] proxiedInterfaces = aopConfig.getProxiedInterfaces();
        return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//        获取目标对象
        Object target = this.aopConfig.getTargetObject();
        Object retVal;
        // Get the interception chain for this method.
        //获取通知点
        List<Advice> chain = this.aopConfig.getAdvices(method);
        // Check whether we have any advice. If we don't, we can fallback on direct
        // reflective invocation of the target, and avoid creating a MethodInvocation.
        if (chain.isEmpty()) {
            // We can skip creating a MethodInvocation: just invoke the target directly
            // Note that the final invoker must be an InvokerInterceptor so we know it does
            // nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
            retVal = method.invoke(target, args);
        } else {
            List<MethodInterceptor> interceptors = new ArrayList<MethodInterceptor>();
            interceptors.addAll(chain);
            // We need to create a method invocation...
            retVal = new ReflectiveMethodInvocation(target, method, args, interceptors).proceed();
        }
        // Massage return value if necessary.
        /*Class<?> returnType = method.getReturnType();
        if (retVal != null && retVal == target && returnType.isInstance(proxy) ) {
            // Special case: it returned "this" and the return type of the method
            // is type-compatible. Note that we can't help if the target sets
            // a reference to itself in another returned object.
            retVal = proxy;
        }
        else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
            throw new AopInvocationException(
                    "Null return value from advice does not match primitive return type for: " + method);
        }*/
        return retVal;
    }
}

说明 JDK代理类必须要实现InvocationHandler 接口。

调用JDK代理的方法在AspectJAutoProxyCreator类

protected Object createProxy(List<Advice> advices, Object bean) {
        AopConfigSupport config = new AopConfigSupport();
        for (Advice advice : advices) {
            config.addAdvice(advice);
        }
        Set<Class> targetInterfaces = ClassUtils.getAllInterfacesForClassAsSet(bean.getClass());
        for (Class<?> targetInterface : targetInterfaces) {
            config.addInterface(targetInterface);
        }
        config.setTargetObject(bean);
        AopProxyFactory proxyFactory = null;
        if (config.getProxiedInterfaces().length == 0) {
            proxyFactory = new CglibProxyFactory(config);
        } else {
            //需要实现JDK代理,有接口的情况下
            proxyFactory=new JdkAopProxyFactory(config);
        }
        return proxyFactory.getProxy();
    }

源码地址

相关文章
|
11月前
|
XML 安全 Java
使用 Spring 的 @Aspect 和 @Pointcut 注解简化面向方面的编程 (AOP)
面向方面编程(AOP)通过分离横切关注点,如日志、安全和事务,提升代码模块化与可维护性。Spring 提供了对 AOP 的强大支持,核心注解 `@Aspect` 和 `@Pointcut` 使得定义切面与切入点变得简洁直观。`@Aspect` 标记切面类,集中处理通用逻辑;`@Pointcut` 则通过表达式定义通知的应用位置,提高代码可读性与复用性。二者结合,使开发者能清晰划分业务逻辑与辅助功能,简化维护并提升系统灵活性。Spring AOP 借助代理机制实现运行时织入,与 Spring 容器无缝集成,支持依赖注入与声明式配置,是构建清晰、高内聚应用的理想选择。
888 0
|
监控 安全 Java
Spring AOP实现原理
本内容主要介绍了Spring AOP的核心概念、实现机制及代理生成流程。涵盖切面(Aspect)、连接点(Join Point)、通知(Advice)、切点(Pointcut)等关键概念,解析了JDK动态代理与CGLIB代理的原理及对比,并深入探讨了通知执行链路和责任链模式的应用。同时,详细分析了AspectJ注解驱动的AOP解析过程,包括切面识别、切点表达式匹配及通知适配为Advice的机制,帮助理解Spring AOP的工作原理与实现细节。
1710 13
|
10月前
|
XML Java 数据格式
《深入理解Spring》:AOP面向切面编程深度解析
Spring AOP通过代理模式实现面向切面编程,将日志、事务等横切关注点与业务逻辑分离。支持注解、XML和编程式配置,提供五种通知类型及丰富切点表达式,助力构建高内聚、低耦合的可维护系统。
|
12月前
|
人工智能 监控 安全
如何快速上手【Spring AOP】?核心应用实战(上篇)
哈喽大家好吖~欢迎来到Spring AOP系列教程的上篇 - 应用篇。在本篇,我们将专注于Spring AOP的实际应用,通过具体的代码示例和场景分析,帮助大家掌握AOP的使用方法和技巧。而在后续的下篇中,我们将深入探讨Spring AOP的实现原理和底层机制。 AOP(Aspect-Oriented Programming,面向切面编程)是Spring框架中的核心特性之一,它能够帮助我们解决横切关注点(如日志记录、性能统计、安全控制、事务管理等)的问题,提高代码的模块化程度和复用性。
|
12月前
|
设计模式 Java 开发者
如何快速上手【Spring AOP】?从动态代理到源码剖析(下篇)
Spring AOP的实现本质上依赖于代理模式这一经典设计模式。代理模式通过引入代理对象作为目标对象的中间层,实现了对目标对象访问的控制与增强,其核心价值在于解耦核心业务逻辑与横切关注点。在框架设计中,这种模式广泛用于实现功能扩展(如远程调用、延迟加载)、行为拦截(如权限校验、异常处理)等场景,为系统提供了更高的灵活性和可维护性。
1460 0
|
Java API 微服务
微服务——SpringBoot使用归纳——Spring Boot中的切面AOP处理——Spring Boot 中的 AOP 处理
本文详细讲解了Spring Boot中的AOP(面向切面编程)处理方法。首先介绍如何引入AOP依赖,通过添加`spring-boot-starter-aop`实现。接着阐述了如何定义和实现AOP切面,包括常用注解如`@Aspect`、`@Pointcut`、`@Before`、`@After`、`@AfterReturning`和`@AfterThrowing`的使用场景与示例代码。通过这些注解,可以分别在方法执行前、后、返回时或抛出异常时插入自定义逻辑,从而实现功能增强或日志记录等操作。最后总结了AOP在实际项目中的重要作用,并提供了课程源码下载链接供进一步学习。
1846 0
|
存储 Ubuntu 安全
在Ubuntu 16.04上安装openjdk-6/7/8-jdk的步骤
在整个安装过程中,你可能需要管理员权限,因此你可能要使用 `sudo` 来获取必要的权限。记得做完每一个步骤后,都要检查输出,以确保没有发生错误,并且每项操作都成功完成。如果在安装过程中遇到问题,查看 `/var/log/` 下的日志文件对于问题的解决可能是有帮助的。
779 21
|
IDE Ubuntu Java
在Ubuntu18.04安装兼容JDK 8的Eclipse集成开发环境的指南。
完成以上步骤后,您将在Ubuntu 18.04系统上成功安装并配置了Eclipse IDE,它将与JDK 8兼容,可以开始进行Java开发工作。如果遇到任何问题,请确保每一步骤都正确执行,并检查是否所有路径都与您的具体情况相匹配。
553 11