6、AOP(spring笔记)

一、AOP中的术语简介

AOP.png

说明:

  • 1.这里我们拿安全性检查来进行说明。对于安全性检查来说,这和我们真正的业务是没有任何关系的,只是我们将其横向插入进去,在spring中这叫横切性关注点(cross cutting concern)。

  • 2.对于横切性关注点来说,我们可以实现各种模块化的类,即切面类(aspect),而我们实现安全性检查的类SecurityHandler类就叫Advice。同时Advice类根据其切入点的不同可以分为Before Advice、After Advice。

  • 3.所谓切入点(pointcut),表示advice能应用咋什么地方,即应用在哪些jointpoint,在spring中指能应用在哪些方法上,因为方法只支持方法的连接点(jointpoint),而应用的过程叫植入(weave)。

  • 4.另外两个术语proxy表示代理,introduction表示动态的给一个类加上一些方法。

二、spring对AOP的支持(采用注解方式)(工程spring_aop_1

  • 1.依赖库
    这里需要在之前依赖包基础上再加上一些依赖包SPRING_HOME/lib/aspectj/*.jar,同时注意:如果JDK版本较高,则低版本的aspectj包可能会出现问题,此时请使用目录中1.8版本的aspectj包。

  • 2.采用aspect注解定义切面;

  • 3.在aspect定义pointcut和advice。

  • 4.启用aspect对注解的支持,同时将切面和目标对象配置到IOC容器中。

动态代理类:SecurityHandler.java

package com.bjsxt.spring;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
/**
 * 定义Aspect
 */
@Aspect
public class SecurityHandler {
    
    /*下面的注解表示应用范围,使用Pointcut注解,而其名称是allAddMethod,
    不能有返回值和参数,该方法只是一个Pointcut标识,没有其他意义。
    *Pointcut的内容是一个表达式,描述应用到哪些方法上(Joinpoint),括
    号里面第一个*号表示
    *返回值(即返回值可有可没有),而add*表示所有的add方法,(..)表示
    任意参数。
    */
    @Pointcut("execution(* add*(..)) || execution(* del*(..))")
    private void allAddMethod(){};
    
    /*检查安全性,注解表示在方法之前调用,而方法使用allAddMethod()标识
     *定义Advice,标识在哪个切入点植入此方法
     * */
    @Before("allAddMethod()")
    private void checkSecurity() {
        System.out.println("----------checkSecurity()---------------");
    }
}

说明:这里一定要注意,切入点方法是不会执行的,存在的目的仅仅是作为一个标识,我们可以在advice中通过此方法名引用此切入点。

配置:

<?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:aop="http://www.springframework.org/schema/aop"
         xmlns:tx="http://www.springframework.org/schema/tx"
         xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
    
    <aop:aspectj-autoproxy/>
    <bean id="securityHandler" class="com.bjsxt.spring.SecurityHandler"/>           
    <bean id="userManager" class="com.bjsxt.spring.UserManagerImpl"/>
</beans>

测试:Client.java

package com.bjsxt.spring;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Client {

    public static void main(String[] args) {
        BeanFactory factory = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserManager userManager = (UserManager)factory.getBean("userManager");
        
        userManager.addUser("张三", "123");
        userManager.deleteUser(1);
    }
}

三、spring对AOP的支持(采用配置方式)(工程spring_aop_2

首先将之前的注解全部取消,然后在配置文件中进行配置:

<?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:aop="http://www.springframework.org/schema/aop"
         xmlns:tx="http://www.springframework.org/schema/tx"
         xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
    
    <bean id="securityHandler" class="com.bjsxt.spring.SecurityHandler"/>           
    
    <bean id="userManager" class="com.bjsxt.spring.UserManagerImpl"/>
    
    <aop:config>
        <aop:aspect id="security" ref="securityHandler">
            <aop:pointcut id="allAddMethod" expression="execution(* com.bjsxt.spring.UserManagerImpl.add*(..))"/>
            <aop:before method="checkSecurity" pointcut-ref="allAddMethod"/>
        </aop:aspect>
    </aop:config>   
</beans>

SecurityHandler.java

package com.bjsxt.spring;
public class SecurityHandler {
    
    private void checkSecurity() {
        System.out.println("----------checkSecurity()---------------");
    }
}

说明:两种配置方式本质上是一样的,我们推荐使用配置文件的方式进行配置。

我们还可以通过advice中添加一个jointpoint参数,这个值会由spring自动传入,从jointpoint中可以取到要检查的方法的参数和方法名(工程spring_aop_3

SecurityHandler.java

package com.bjsxt.spring;
import org.aspectj.lang.JoinPoint;
public class SecurityHandler {
    
    private void checkSecurity(JoinPoint joinPoint){
        
        //此时我们就可以拿到对某个方法进行安全性检查的参数和方法名字
        //比如addUser("Tom", "123");中的参数"Tom"和"123"和方法名
        //addUser
        Object[] args = joinPoint.getArgs();
        for(int i = 0; i < args.length; i++){
            System.out.println(args[i]);
        }
        
        System.out.println(joinPoint.getSignature().getName());//拿到方法签名
        System.out.println("----UserManagerImpl.checkSecurity()---");
    }
}

四、使用CGLIB库实现动态代理(工程spring_aop_4

  • 1.如果目标对象实现了接口(比如这里的业务类),默认情况下会采用JDK的动态代理实现AOP;

  • 2.如果目标对象实现了接口,也可以强制使用CGLIB实现AOP;

  • 3.没有实现接口那就必须使用CGLIB实现AOP了,spring会自动在JDK动态代理和CGLIB之间转换,就是实现了接口的使用JDK动态代理,没有实现接口的使用CGLIB实现,spring自动完成此转换。

4.1 强制使用CGLIB实现动态代理

  • 添加CGLIB库
  • 在spring的配置文件中进行配置:<aop:aspectj-autoproxy proxy-target-class="true"/>,此时我们会发现实现的代理类就是由CGLIB实现的。当然我们还是推荐使用JDK的动态代理,这就要求我们实现接口。

4.2 JDK动态代理和CGLIB字节码生成的区别:

  • JDK动态代理只能对实现了接口的类生成代理,不能针对类生成代理
  • CGLIB是针对类实现代理,实现原理是生成一个子类作为一个代理。因为是继承,所以该类或方法最好不要声明成final类型。实际中我们建议使用JDK的动态代理。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,869评论 18 139
  • 什么是Spring Spring是一个开源的Java EE开发框架。Spring框架的核心功能可以应用在任何Jav...
    jemmm阅读 16,549评论 1 133
  • 上一篇:Spring学习笔记(六、Spring AOP基本概念) 一、Spring AOP API 这是Sprin...
    鲁克巴克诗阅读 1,643评论 0 2
  • title: Spring_AOP源码分析date: 2016-11-03 01:15:11categories:...
    raincoffee阅读 1,769评论 2 36
  • 从三月份找实习到现在,面了一些公司,挂了不少,但最终还是拿到小米、百度、阿里、京东、新浪、CVTE、乐视家的研发岗...
    时芥蓝阅读 42,356评论 11 349