循序渐进之Spring AOP(1) - 原理

AOP全称是Aspect Oriented Programing,通常译为面向切面编程。利用AOP可以对面向对象编程做很好的补充。

用生活中的改装车比喻,工厂用面向对象的方法制造好汽车后,车主往往有些个性化的想法,但是又不想对车进行大规模的拆卸、替换零件,这时可以买一些可替换的零件、装饰安装到汽车上,并且这些改装应该很容易拆卸,以避免验车时无法通过。

先看一个实际例子:有一个用户登录的方法,某一段时间内我们希望能够临时监控执行时间,但是又不想直接在方法上修改,用AOP方案实现如下。

UserService类

用sleep随机时间来模拟用户登录消耗的时间

import java.util.Random;

public class UserService {
    public void login(String userName, String password) {
        try {
            Thread.sleep(new Random(47).nextInt(100));
        } catch (InterruptedException e) {}
        System.out.println("UserService: 用户" + userName + "登录成功");
    }
}

PerformanceMonitorUserService类,Spring将把它当作UserService的替身(代理,Proxy)

import java.util.concurrent.TimeUnit;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class PerformanceMonitorUserService {

    @Around("execution(* login(..))")
    public void aroundLogin(ProceedingJoinPoint pjp) {
        String userName = pjp.getArgs()[0].toString();
        long begin = System.nanoTime();
        try {
            pjp.proceed();
        } catch (Throwable e) {
            e.printStackTrace();
        }
        long end = System.nanoTime();
        System.out.println("PerformanceMonitorUserService: 用户" + userName + "登录耗时" + TimeUnit.MILLISECONDS.convert((end - begin), TimeUnit.NANOSECONDS) + "毫秒");
    }
}

applicationContext.xml,放在src根目录

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
  http://www.springframework.org/schema/aop
  http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

    <aop:aspectj-autoproxy />
    <bean id="userService" class="demo.aop.UserService" />
    <bean class="demo.aop.PerformanceMonitorUserService" />
</beans>

需要添加的jar包

测试代码

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Client {

    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService userService = (UserService)ctx.getBean("userService");
        userService.login("Tom", "123456");
    }
}

UserService: 用户Tom登录成功
PerformanceMonitorUserService: 用户Tom登录耗时71毫秒
这样就保持了UserService业务的纯粹性,避免非业务代码和业务代码混合在一起。如果希望取消时间监控,只需要删除applicationContext里的<bean class="demo.aop.PerformanceMonitorUserService" />即可。

Spring是如何做到的呢?底层的两大功臣是JDK的动态代理和CGLib动态代理技术。我们以JDK的动态代理技术来重现上面的过程

UserService接口(JDK动态代理只能为接口创建代理,所以先抽象了一个接口)

public interface UserService {
    void login(String userName, String password);
}

实现类

import java.util.Random;

public class UserServiceImpl implements UserService {

    public void login(String userName, String password) {
        try {
            Thread.sleep(new Random(47).nextInt(100));
        } catch (InterruptedException e) {}
        System.out.println("UserService: 用户" + userName + "登录成功");
    }
}

代理类

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

public class PerformanceMonitorUserService implements InvocationHandler {
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        long begin = System.currentTimeMillis();
        Object obj = method.invoke(target, args);
        long end = System.currentTimeMillis();
        System.out.println("PerformanceMonitorUserService: 用户" + args[0] + "登录耗时" + TimeUnit.MILLISECONDS.convert((end - begin), TimeUnit.NANOSECONDS) + "毫秒");
        return obj;
    }

    private Object target;
    public PerformanceMonitorUserService(Object target) {
        this.target = target;
    }

}

测试代码

import java.lang.reflect.Proxy;

public class Client {

    public static void main(String[] args) {
        UserService target = new UserServiceImpl();
        PerformanceMonitorUserService handler = new PerformanceMonitorUserService(target);
        UserService proxy = (UserService)Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(), handler);
        proxy.login("Tom", "123456");
    }
}

从上面的代码可以看出,AOP的原理就是创建代理,在运行时我们开发的业务逻辑类已经被替换成添加了增强代码的代理类,而Spring帮我们省略了这些繁琐和重复的步骤。

---------------------
作者:大雨将至
来源:CSDN
原文:https://blog.csdn.net/autfish/article/details/51068062/
版权声明:本文为博主原创文章,转载请附上博文链接!

原文地址:https://www.cnblogs.com/sandea/p/11176976.html

时间: 2024-12-15 16:35:32

循序渐进之Spring AOP(1) - 原理的相关文章

Spring AOP底层原理

------------------siwuxie095 Spring AOP 底层原理 AOP 即 Aspect Oriented Programming,面向切面编程, 即 不通过修改源代码的方式扩展功能 「在不修改源代码的情况下,对程序进行增强」 2.AOP 采取横向抽取机制,取代了传统纵向继承体系重复性 代码 3.AOP 底层原理所使用的技术 (1)JDK 的动态代理:针对实现了接口的类产生代理 即 有接口,使用动态代理创建接口实现类的代理对象 (2)CGLIB 的动态代理:针对没有实现

Spring AOP 实现原理(二) 使用 Spring AOP

与 AspectJ 相同的是,Spring AOP 同样需要对目标类进行增强,也就是生成新的 AOP 代理类:与 AspectJ 不同的是,Spring AOP 无需使用任何特殊 命令对 Java 源代码进行编译,它采用运行时动态地.在内存中临时生成"代理类"的方式来生成 AOP 代理. Spring 允许使用 AspectJ Annotation 用于定义方面(Aspect).切入点(Pointcut)和增强处理(Advice),Spring 框架则可识别并根据这些 Annotati

Spring AOP 实现原理与 CGLIB 应用--转

AOP(Aspect Orient Programming),作为面向对象编程的一种补充,广泛应用于处理一些具有横切性质的系统级服务,如事务管理.安全检查.缓存.对象池管理等.AOP 实现的关键就在于 AOP 框架自动创建的 AOP 代理,AOP 代理则可分为静态代理和动态代理两大类,其中静态代理是指使用 AOP 框架提供的命令进行编译,从而在编译阶段就可生成 AOP 代理类,因此也称为编译时增强:而动态代理则在运行时借助于 JDK 动态代理.CGLIB 等在内存中“临时”生成 AOP 动态代理

Spring AOP 实现原理(一) 使用 AspectJ 的编译时增强进行 AOP

AOP(Aspect Orient Programming),也就是面向方面编程,作为面向对象编程的一种补充,专门用于处理系统中分布于各个模块(不同方法)中的 交叉关注点的问题,在 JavaEE 应用中,常常通过 AOP 来处理一些具有横切性质的系统级服务,如事务管理.安全检查.缓存.对象池管理等.AOP 实现的关键就在于 AOP 框架自动创建的 AOP 代理,AOP 代理主要分为静态代理和动态代理两大类,静态代理以 AspectJ 为代表:而动态代理则以 Spring AOP 为代表.本文会从

【转】Spring AOP 实现原理与 CGLIB 应用

AOP(Aspect Orient Programming),作为面向对象编程的一种补充,广泛应用于处理一些具有横切性质的系统级服务,如事务管理.安全检查.缓存.对象池管理等.AOP 实现的关键就在于 AOP 框架自动创建的 AOP 代理,AOP 代理则可分为静态代理和动态代理两大类,其中静态代理是指使用 AOP 框架提供的命令进行编译,从而在编译阶段就可生成 AOP 代理类,因此也称为编译时增强:而动态代理则在运行时借助于 JDK 动态代理.CGLIB 等在内存中"临时"生成 AOP

Spring AOP实现原理与CGLIB应用(转)

AOP(Aspect Orient Programming),作为面向对象编程的一种补充,广泛应用于处理一些具有横切性质的系统级服务,如事务管理.安全检查.缓存.对象池管理等.AOP 实现的关键就在于 AOP 框架自动创建的 AOP 代理,AOP 代理则可分为静态代理和动态代理两大类,其中静态代理是指使用 AOP 框架提供的命令进行编译,从而在编译阶段就可生成 AOP 代理类,因此也称为编译时增强:而动态代理则在运行时借助于 JDK 动态代理.CGLIB 等在内存中“临时”生成 AOP 动态代理

Spring AOP 实现原理(三) 使用 使用 CGLIB 生成代理类

CGLIB(Code Generation Library),简单来说,就是一个代码生成类库.它可以在运行时候动态是生成某个类的子类. 此处使用前面定义的 Chinese 类,现在改为直接使用 CGLIB 来生成代理,这个代理类同样可以实现 Spring AOP 代理所达到的效果. 下面先为 CGLIB 提供一个拦截器实现类: public class AroundAdvice implements MethodInterceptor { public Object intercept(Obje

java框架篇---spring AOP 实现原理

什么是AOP AOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善.OOP引入封装.继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合.当我们需要为分散的对象引入公共行为的时候,OOP则显得无能为力.也就是说,OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系.例如日志功能.日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无

Spring AOP 实现原理

什么是AOP AOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善.OOP引入封装.继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合.当我们需要为分散的对象引入公共行为的时候,OOP则显得无能为力.也就是说,OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系.例如日志功能.日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无