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的动态代理。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容

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