深入理解Spring AOP

一、AOP的概念

  AOP(Aspect Oriented Programming),意思是面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的技术。使用AOP技术,可以将一些与系统相关的业务逻辑功能模块,提取出来,独立实现,然后通过切面切入进系统。从而避免了在核心业务逻辑的代码中混入很多的系统相关的逻辑——比如事务管理(Transaction Management)、安全管理(Security)、日志管理(Logging)和调试管理(Debugging)等等。
  

二、AOP的实现原理是什么

  AOP主要是通过代理模式来实现,主要分为JDK动态代理和CGLib动态代理。下面我们的详细了解一下这两种代理模式的原理。
  

1、JDK动态代理

  JDK动态代理主要涉及到java.lang.reflect包中的两个类:ProxyInvocationHandler。   

  • nvocationHandler是一个接口,通过实现该接口定义横切逻辑,并通过反射机制调用目标类的代码,动态将横切逻辑和业务逻辑编制在一起。   

  • Proxy利用InvocationHandler动态创建一个符合某一接口的实例,生成目标类的代理对象。

下面是JDK动态代理的类图:

这里写图片描述

  根据上面的类图 ,下面我们通过一个查看员工工资系统的示例代码了解JDK的动态代理。在工资系统中业务逻辑包括。查看员工工资、系统安全、操作权限和日志管理。其中主要核心业务逻辑是查看员工的工资。

 1. 查看员工工资

//定义的SalaryManager接口
public interface SalaryManager {
    public void showSalary();
}
//接口SalaryManager的具体实现类
public class SalaryManagerImpl implements SalaryManager{
    public void showSalary() {
        System.out.println("show salary");
    }
}

2. 系统安全

public class Security  {
    public void security(){
        System.out.println("security");
    }
}

3.操作权限

public class Privilege {
    private String access;

    public String getAccess() {
        return access;
    }

    public void setAccess(String access) {
        this.access = access;
    }
}

4.日志管理

public class Logger {
    public void logging(){
        System.out.println("logging");
    }
}

5.实现InvocationHandler接口,将所有的业务逻辑组合在一起

public class MyInterceptor implements InvocationHandler{
    private Object target;
    private Logger logger;
    private Security security;
    private Privilege privilege;
    public MyInterceptor(Object target, Logger logger, Security security,
            Privilege privilege) {
        super();
        this.target = target;
        this.logger = logger;
        this.security = security;
        this.privilege = privilege;
    }
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        /**
         * 1、启动日志
         * 2、启动安全性的类
         * 3、验证权限
         *      调用目标对象的目标方法
         */
        this.logger.logging();
        this.security.security();
        if("admin".equals(this.privilege.getAccess())){
            method.invoke(target);//动态调用目标方法
        }else{
            System.out.println("没有权限查看工资");
        }
        return null;
    }
}

6.使用Proxy接口 ,生成目标类的代理对象

public class SalaryTest {
    @Test
    public void testSalary(){
        Object target = new SalaryManagerImpl();
        Logger logger = new Logger();
        Security security = new Security();
        Privilege privilege = new Privilege();
        privilege.setAccess("asfd");
        MyInterceptor interceptor = new MyInterceptor(target, logger, security, privilege);
        SalaryManager  proxy = (SalaryManager)Proxy.newProxyInstance(
                    target.getClass().getClassLoader(), 
                    target.getClass().getInterfaces(), interceptor);
        proxy.showSalary();
    }
}

2、CGLib动态代理

  CGLib全称为Code Generation Library,是一个强大的高性能,高质量的代码生成类库,可以在运行期扩展Java类与实现Java接口,CGLib封装了asm,可以再运行期动态生成新的class。和JDK动态代理相比较:JDK创建代理有一个限制,就是只能为接口创建代理实例,而对于没有通过接口定义业务方法的类,则可以通过CGLib创建动态代理。
(备注:其代码演示就不在此赘述)

3、JDK和CGLib动态代理区别

JDK和CGLib动态代理区别主要体现在以下两点

  • JDK动态代理只能对实现了接口的类生成代理,而不能针对类

  • CGLIB是针对类实现代理,生成代理类是目标类的子类

备注:在Spring中对于AOP代理类的生成原则是:
   如果目标对象的实现类实现了接口,Spring AOP 将会采用 JDK 动态代理来生成 AOP 代理类;
   如果目标对象的实现类没有实现接口,Spring AOP 将会采用 CGLIB 来生成 AOP 代理类

三、在Spring中AOP的配置方式

首先,我们结合上述查看员工工资的系统实例代码来看一下,AOP中的一些重要概念

  • 切面(Aspect):就是除了核心关注点之外所有操作。例如 : Security ,Privilege 类就是切面。“切面”在ApplicationContext中来配置。
  • 连接点(Joinpoint) :目标类的中方法 。例如SalaryManager中的 showSalary()方法。
  • 通知(Advice) :“切面”对于某个“连接点”所产生的动作,其实,就是切面中方法。例如:Security 类中security()方法。
  • 切入点(Pointcut) :匹配连接点的断言,在AOP中通知和一个切入点表达式关联。就相当于条件判断语句。例如:在上述testSalary 中 if(“admin”.equals(this.privilege.getAccess()))而在 都由切入点表达式execution(* com.spring.service..(..))来决定

Spring中AOP实现在XML中的配置方式示例:

<tx:advice transaction-manager="transationManager" id="tx">
          <tx:attributes>
            <tx:method name="save*" propagation="REQUIRED" rollback-for="java.lang.Exception"/>
            <tx:method name="update*" propagation="REQUIRED"  rollback-for="java.lang.Exception"/>
            <tx:method name="delete*" propagation="REQUIRED"  rollback-for="java.lang.Exception"/>
            <tx:method name="*" propagation="REQUIRED" read-only="true"/>
        </tx:attributes>
        </tx:advice>

        <aop:config>
           <aop:pointcut expression="execution(* com.ywendeng.ecs.service.*.*(..))" id="perfrom"/>
            <aop:advisor advice-ref="tx" pointcut-ref="perfrom"/>
        </aop:config>  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值