还在面向对象,面向切片了解一下

1、什么是AOP?(是什么)

   Aspect OrientedProgramming的缩写,意思就是:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。这种在运行时,动态地将代码切入到类的指定方法、指定位置上的编程思想就是面向切面的编程。它是一种编程范式,一种编程思想。AOP是Spring提供的关键特性之一。对了,有人提到这个和拦截器有什么关系,注意AOP是一种编程思想,拦截器就是基于这种编程思想实现的。

基本概念:
    切面(Aspect):一个关注点的模块化,这个关注点可能会横切多个对象。

    连接点(Joinpoint):程序执行过程中的某个特定的点

    通知(Advice):在切面的某个特定的连接点上执行的动作。
image
    切入点(Pointcut): 匹配连接点的断言,在AOP中通知和一个切入点表达式的关联。

    引入(Introduction)在不修改类代码的前提下,为类添加新的方法和属性。

    目标对象(target Object)被一个或者多个切面所通知的对象

      AOP代理(Aop proxy)AOP框架创建的对象,用来实现切面契约(aspectcontract)包括通知放法执行等功能。

   织入(weaving)  把切面连接到其他的应用程序类型或者对象上,并创建一个被通知的对象,分为编制时织入,类加载时织入,执行时织入。

2、aop编程思想的作用!(为什么)

   其实aop就是对OOP编程的有效补充。其实最终目的是实现程序的解耦。但是OOP一般允许开发者定义纵向的关系,但并不适合定义横向关系,使用AOP技术可以将一些系统性相关的编程工作、独立提取出来,独立实现,然后通过切面切入进系统。从而避免了在业务逻辑的代码中混入很多的系统相关的逻辑——比如权限管理,事物管理,日志记录等等。这些系统性的编程工作都可以独立编码实现,然后通过AOP技术切入进系统即可。从而达到了 将不同的关注点分离出来的效果。

image

   如上图,我们可以将日志以及权限这种分离出来,然后在需要用到的这些核心功能模块中横向的切入进去,这样对于核心模块是无感的,这样的话讲大大降低系统的耦合性和复杂性,试想如果这些模块散落在各个核心业务中,如果出现大的改动,必然会产生极大的维护成本,需要每一处都进行修改。

3、实现方式

** 方式一:**@AspectJ注解驱动的切面,这个是一种静态代理的方式

   Java通过Java编译器将.java源文件编译成.class字节码文件,这种.class文件是二进制文件,内容是只有JVM虚拟机能够识别的机器码,JVM虚拟机读取字节码文件,取出二进制数据,加载到内存中,解析.class文件内的信息,生成对应的Class对象,进而使Class对象创建类的具体实例来进行调用实现具体的功能。
   所以这种方式就是在java编译成class的时候去实现代理。性能上很高效,但是没有不太灵活。
   这种方式我的理解就是在编译器将切片插入到对应的函数栈中(仅仅自己的理解)

** 方式二:**运行期动态代理,(JDK动态代理,CGLib动态代理)

  1. 纯jiava的实现,无需特殊的编译过程,不需要控制类加载器层次。

  2. 目前只支持放法执行连接点,(通知spring bean的方法的执行)

  3. 不是提供一个最完整的AOP实现尽管它已经非常强大,而是侧重用于提供一种AOP实现和SpringIOC容器之间的整合,用于帮助解决企业应用中常见的问题。

  4. Spring AOP 不会和Aspect竞争,从而提供综合全面的AOP解决方案。

image

   spring中AOP代理由Spring的IOC容器负责生成,管理,其依赖关系也是由IOC容器负责管理的,因此,AOP代理可以直接使用容器中的其他bean实例作为目标,这种关系可由IOC容器的依赖注入提供,Spring创建代理的规则为:

1)、默认使用java动态代理来创建AOP代理,这样就可以为任何接口实例创建代理了。
2)、当需要代理的类不是代理接口的时候,Spring会切换为使用CGLB代理,也可强制使用CGLIB(CGLIB是一个强大的、高性能的代码生成库)

4、应用场景

image

   其实这里有点多余,aop是一种编程思想,你可以在很多场景中去使用,但是还是想给大家一个直观的感受。

5、在sping中使用切面编程。(怎么用?)

基于@AspectJ注解的AOP实现
   这里主要是采用这种方式来演示aop的实现过程,来直观的体会aop实现的思想。

step1:引用依赖

    <!--aop    aspectj-->   
 <!-- https://mvnrepository.com/artifact/aopalliance/aopalliance -->
    <dependency>        
       <groupId>aopalliance</groupId> 
       <artifactId>aopalliance</artifactId>
       <version>1.0</version>
    </dependency>    
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aspects</artifactId>
        <version>5.1.3.RELEASE</version>
    </dependency>

Step2:创建测试类

IAopTest.java 接口

package com.mjcc.spring.aop;
/** 
* @Description:
* @Author: chengcheng 
* @Date: Create in 8:40 2019/7/28
* @Modified By: 
*/
public interface IAopTest {
    public int add(int a, int b);
    public int sub(int a, int b);
}

AopTestImpl.java 实现类

package com.mjcc.spring.aop;import org.springframework.stereotype.Component;
/**
 * @Description:
 * @Author: chengcheng
 * @Date: Create in 8:42 2019/7/28
 * @Modified By:
 */
@Component("aopTest")
public class AopTestImpl implements IAopTest {
    public int add(int a, int b) {
        int res = a + b; 
        return res;
    }
    public int sub(int a, int b) { 
        int res = a - b;
        return res;
    }
}

LoggerAspect.java // 日志的切面编程

package com.mjcc.spring.aop;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;import java.util.Arrays;
import java.util.List;
/** 
* @Description: 
* @Author: chengcheng 
* @Date: Create in 8:59 2019/7/28 
* @Modified By:
 */
@Aspect     
// 告诉spring  这是一个切面类,就是横切关注点的集合,与核心业务代码无关的日志,权限,事务代码 集中起来组成切面
@Componentpublic
 class LoggerAspect {
    private Logger logger = Logger.getLogger(this.getClass());
    // 指定beforeMethod在哪个类中的哪个方法前切入执行 
   // @Before的参数里,写一个切入点表达式,来告诉spring 要将下面的方法切入到哪个类的哪个方法前面执行
    @Before("execution(public int com.mjcc.spring.aop.AopTestImpl.add(int, int))")
    @Before("execution(public int com.mjcc.spring.aop.AopTestImpl.*(int, int))")
    public void beforeMethod(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName(); // 拿到切入点的的方法名 
        List<Object> args = Arrays.asList(joinPoint.getArgs());
        logger.info(methodName + "方法运算执行之前。。。。。。。" + args);
    }
}

测试base类

package com.mjcc.spring.base;

import org.junit.After;
import org.junit.Before;
import org.springframework.beans.BeansException;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.util.StringUtils;

/**
 * @Description:
 * @Author: chengcheng
 * @Date: Create in 14:18 2019-04-13
 * @Modified By:
 */
public class UnitTestBase {
    private ClassPathXmlApplicationContext context;
    private String springXmlPath;
    public UnitTestBase () {
    }

    public UnitTestBase(String springXmlPath) {
        this.springXmlPath = springXmlPath;
    }

    @Before // 初始化方法,执行当前测试类的每个测试方法前执行
    public void before () {
        if (StringUtils.isEmpty(springXmlPath)) {
            springXmlPath = "classpath*:spring-*.xml";
        }
        try {
            context = new ClassPathXmlApplicationContext(springXmlPath.split("[,\\s]+"));
            context.start();
        } catch (BeansException e) {
            e.printStackTrace();
        }
    }

    @After //释放资源,执行当前测试类的每个测试方法后执行
    public void after () {
        context.destroy();
    }

    @SuppressWarnings("unchecked")
    protected  <T extends Object> T getBean (String beanId) {
        try {
            return (T)context.getBean(beanId);
        } catch (BeansException e) {
            e.printStackTrace();
            return null;
        }
    }

    protected <T extends Object> T getBean (Class<T> clazz) {
        try {
            return context.getBean(clazz);
        } catch (BeansException e) {
            e.printStackTrace();
            return null;
        }
    }


}

测试类:

package com.mjcc.spring.aop;

import com.mjcc.spring.base.UnitTestBase;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.BlockJUnit4ClassRunner;

/**
 * @Description:
 * @Author: chengcheng
 * @Date: Create in 8:47 2019/7/28
 * @Modified By:
 */
@RunWith(BlockJUnit4ClassRunner.class)
public class AopTestImplTest extends UnitTestBase {
    public AopTestImplTest () {
        super("applicationContext.xml");
    }
    @Test
    public void AopTest () {
        IAopTest aopTest = (IAopTest) super.getBean("aopTest");
        System.out.println("add :  " + aopTest.add(1, 1));
        System.out.println("sub :  " + aopTest.sub(8, 5));
    }
}

xml配置

<?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:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    <context:component-scan base-package="com.mjcc.spring"></context:component-scan>
    <!--自动生成aspecyj 动态代理-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

</beans>

切入点:

  • @Before和它注解的这个方法在AOP中叫做通知,在上面基础概念中已经提到了, before属于前置通知。

还有下面这些通知,

  • @After 后置通知,在目标方法执行之后执行

  • @AfterReturning 返回通知,(在目标方法返回结果之后执行)

  • @AfterThrowing异步通知,在目标方法抛出异常之后执行

  • @Around 环绕通知

   对了,注意一个问题,当同一个目标方法有多个切面的时候,到底是哪个先执行,这个顺序可以使用@Order注解来注解切入类,值越小,越先执行。@Order(1) > @Order(2)

个人拙见,望指教。
关注公众号回复获取“java入门就业”获取一套个人收藏的java视频教程 ,

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

推荐阅读更多精彩内容