AOP的奇妙之处

Posted 花式编程

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AOP的奇妙之处相关的知识,希望对你有一定的参考价值。

参考:http://sishuok.com/forum/blogPost/list/2467.html

blog.csdn.net/qq525099302/article/details/53996344

早之前和朋友聊天,朋友说他写了几天的代码,写了好多,然后给组长看,组长说都删掉吧,然后用AOP,用几行代码就搞定,非常帅,有木有!
后来就一直想学,由于工作原因,和项目没有用到就一直没认真学习,只是略知皮毛,这几天认真学习,从最基层学习,把自己学习心得贴在这里供大家一起学习!

首先贴一张图来展现一下AOP的作用:

AOP的奇妙之处

我们传统的编程方式是垂直化的编程,即A->B->C->D这么下去,一个逻辑完毕后执行另外一段逻辑,但是AOP提供了另外一种思路。它的作用是在业务逻辑不知情的情况下对业务代码的功能进行增强,这种编程思想的使用场景有很多,例如事物提交,方法执行之前的权限检测,日志打印,方法调事件等等。

其次我用一个简单的最基础的例子来展现AOP的作用:

1.首先配置pom.xml

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <spring.version>4.1.3.RELEASE</spring.version>
</properties>
<dependencies>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>4.1.3.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>${spring.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-beans</artifactId>
      <version>${spring.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>${spring.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>${spring.version}</version>
    </dependency>

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aspects</artifactId>
      <version>${spring.version}</version>
    </dependency>
</dependencies>

2.定义目标类:

public interface IHelloWorldService {
    public void sayHello();
}

3.定义目标接口实现

public class HelloWorldService implements  IHelloWorldService {
    @Override
    public void sayHello() {
        System.out.println("-----Hello World------");
    }
}

4.定义切面接口类:

public class HelloWorldAspect {
    //前置通知
    public void beforeAdvice(){
        System.out.println("------before advice");
    }
    //后置最终通知
    public void afterFinallyAdvice(){
        System.out.println("------after finally advice");
    }
}

5.在xml中进行配置:

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

        <!--配置目标类-->
    <bean id="helloWorldService" class="spring.service.HelloWorldService"></bean>
    <!--配置切面-->
    <bean id="aspect" class="spring.service.HelloWorldAspect"></bean>
//第一种方法:expression="within(spring.service.*)定义在service包下的任意类的执行
    <aop:config>
        <aop:pointcut id="pointcut" expression="within(spring.service.*)"></aop:pointcut>
        <aop:aspect ref="aspect">
            <aop:before pointcut-ref="pointcut" method="beforeAdvice"></aop:before>
            <aop:after pointcut="within(spring.service.*)" method="afterFinallyAdvice"></aop:after>
        </aop:aspect>
    </aop:config>
//第二种方法:expression="execution(* spring.service.*.*(..))定义在service包里的任意方法的执行
  <aop:config>
        <aop:pointcut id="pointcut" expression="execution(* spring.service.*.*(..))"/>
        <aop:aspect ref="aspect">
            <aop:before pointcut-ref="pointcut" method="beforeAdvice"></aop:before>
            <aop:after pointcut="execution(* spring.service.*.*(..))" method="afterFinallyAdvice"></aop:after>
        </aop:aspect>
    </aop:config>
<beans>

6.测试代码:

public class AopTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("helloworld.xml");
        IHelloWorldService helloWorldService = context.getBean("helloWorldService", IHelloWorldService.class);
        helloWorldService.sayHello();
    }
}

输出结果

AOP的奇妙之处

从输出我们可以看出:前置通知在切入点选择的连接点(方法)之前允许,而后置通知将在连接点(方法)之后执行,具体生成AOP代理及执行过程如下图:

AOP的奇妙之处

最后附上 Spring AOP中pointcut exception表达式解析及配置

任意公共方法的执行:
execution(public * *(..))
任何一个以“set”开始的方法的执行:
execution(* set*(..))
AccountService 接口的任意方法的执行:
execution(* com.xyz.service.AccountService.*(..))
定义在service包里的任意方法的执行:
execution(* com.xyz.service.*.*(..))
定义在service包和所有子包里的任意类的任意方法的执行:
execution(* com.xyz.service..*.*(..))
定义在pointcutexp包和所有子包里的JoinPointObjP2类的任意方法的执行:
execution(* com.test.spring.aop.pointcutexp..JoinPointObjP2.*(..))")
***> 最靠近(..)的为方法名,靠近.*(..))的为类名或者接口名,如上例的JoinPointObjP2.*(..))

pointcutexp包里的任意类.
within(com.test.spring.aop.pointcutexp.*)
pointcutexp包和所有子包里的任意类.
within(com.test.spring.aop.pointcutexp..*)
实现了MyInterface接口的所有类,如果MyInterface不是接口,限定MyInterface单个类.
this(com.test.spring.aop.pointcutexp.MyInterface)
***> 当一个实现了接口的类被AOP的时候,用getBean方法必须cast为接口类型,不能为该类的类型.

带有@MyTypeAnnotation标注的所有类的任意方法.
@within(com.elong.annotation.MyTypeAnnotation)
@target(com.elong.annotation.MyTypeAnnotation)
带有@MyTypeAnnotation标注的任意方法.
@annotation(com.elong.annotation.MyTypeAnnotation)
***> @within和@target针对类的注解,@annotation是针对方法的注解

参数带有@MyMethodAnnotation标注的方法.
@args(com.elong.annotation.MyMethodAnnotation)
参数为String类型(运行是决定)的方法.
args(String)

还有好多好多需要我们学习的,这里就不赘述了,有什么不懂得可以加群一起学习:

点击图片查看更多推荐内容

↓↓↓

Java-GC工作原理


有趣的一题

怎么样才算一个靠谱的程序员

以上是关于AOP的奇妙之处的主要内容,如果未能解决你的问题,请参考以下文章

Gradle的奇妙之处

table的奇妙之处 - 01

算法笔记异或运算的奇妙之处

小议webpack下的AOP式无侵入注入

namedtuple工厂函数,创造一个像实例对象的元祖(感觉到了Python的奇妙与可爱之处)。

JAVA之AOP