Spring AOP详解(示例)

一、什么是AOP
  AOP(Aspect-Oriented Programming), 即 面向切面编程, 它与 OOP( Object-Oriented Programming, 面向对象编程) 相辅相成, 提供了与 OOP 不同的抽象软件结构的视角.在 OOP 中, 我们以类(class)作为我们的基本单元, 而 AOP 中的基本单元是 Aspect(切面)。
二、AOP的优点
  它利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其名为“Aspect”,即切面。所谓“切面”,简单地说,就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。
三、AOP的相关术语
1.通知(Advice):
  所谓通知指的就是指拦截到连接点之后要执行的代码(比如我们拦截到用户点击登录事件,然后我们需要判断登录的账号密码是否合法,是否合法的逻辑就在Advice的方法中实现,也就是拦截到连接到后要做什么处理,都在这里实现),通知分为前置、后置、异常、最终、环绕通知五类。
2.连接点(Joinpoint):
  用于定义通知(Advice)应该切入到哪些连接点(JoinPoint)上。不同的通知通常需要切入到不同的连接点上,一般为一个方法。
3.切入点(Pointcut):
  通知定义了切面要发生的“故事”和时间(定义了what和when),那么切入点就定义了“故事”发生的地点(where),例如某个类或方法的名称,spring中允许我们方便的用正则表达式来指定。
4.切面(Aspect):
  通知和切入点共同组成了切面,切面可能包含很多切入点
5.织入(Weaving):
  组装切面来创建一个被通知对象。
完成时机:可以在编译时完成(例如使用AspectJ编译器),也可以在运行时完成。Spring和其他纯Java AOP框架一样,在运行时完成织入。
6.引入(Introduction)
  引入允许我们向现有的类添加新的方法和属性(Spring提供了一个方法注入的功能)
7.目标(Target)
  即被通知的对象,如果没有AOP,那么它的逻辑将要交叉别的事务逻辑,有了AOP之后它可以只关注自己要做的事(AOP让他做爱做的事)
8.代理(proxy)
  应用通知的对象
三、基于XML配置的AOP实例
  上面的概念主要用于理解,网上很多,可以自己去理解。下面主要来用实例演示SpringAOP。
1.添加所需的jar包(可以使用maven依赖仓库帮你下载,我这里就自己一个个下载的)
      这里写图片描述
  注意:不能少了aspectjweaver包,否则会报错
2.创建项目(SpringAOPTest)
代码没什么业务逻辑只是一些打印操作,这里把代码贴出来。
HelloWorld(处理业务逻辑)

package com.xxx.aop;
/**
 *@description
 *@author create by xiaoxsen
 *@date   2017年8月14日---下午1:59:17
 */
public class HelloWorld {
  public void print()
  {
      System.out.println("helloworld");
  }
}

Logger(横切面关注点)

package com.xxx.aop;
/**
*@author create by xiaoxsen
*@date   2017年8月14日---下午12:28:05
*/
public class Logger {

    public void printBefore(){
        System.out.println("执行前CurrentTime: "+System.currentTimeMillis());
    }
    public void printAfter(){
        System.out.println("执行后CurrentTime: "+System.currentTimeMillis());
    }
}

Test(测试类)

package com.xxx.aop;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 *@description
 *@author create by xiaoxsen
 *@date   2017年8月14日---下午2:00:18
 */
public class Test {
  public static void main(String[] args) {
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    HelloWorld h = (HelloWorld) context.getBean("helloworld");
    h.print();
  }
}

XML配置文件(applicationContext.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: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-4.2.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">
    <bean id="helloworld" class="com.xxx.aop.HelloWorld"></bean>
    <bean id="logger" class="com.xxx.aop.Logger"></bean>
    <!-- aop配置 -->
    <aop:config>
        <!-- 切入点配置 -->
        <aop:pointcut expression="execution(* com.xxx.aop.HelloWorld.* (..))" id="addPrint"/><!--织入到HelloWorld的所有方法,方法可以自己定制-->
        <aop:aspect id="log" ref="logger">
            <!-- 通知配置 -->
            <aop:before method="printBefore" pointcut-ref="addPrint"/>
            <aop:after method="printAfter" pointcut-ref="addPrint"/>
        </aop:aspect>

    </aop:config>

</beans>

运行结果:

执行前CurrentTime: 1502692311935
helloworld
执行后CurrentTime: 1502692311951

四、基于注解的AOP实例
HelloWorld(处理业务逻辑)

package com.xxx.aop;

import org.springframework.stereotype.Service;

/**
 *@description
 *@author create by xiaoxsen
 *@date   2017年8月14日---下午1:59:17
 */
@Service
public class HelloWorld {
  public void print()
  {
      System.out.println("helloworld");
  }
}

Logger(横切面关注点)

package com.xxx.aop;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/**
*@author create by xiaoxsen
*@date   2017年8月14日---下午12:28:05
*/
//指定切面的优先级,当有多个切面时,数值越小优先级越高
@Order(1)
//把这个类声明为一个切面:需要把该类放入到IOC容器中。再声明为一个切面.
@Aspect
@Component
public class Logger {
     /**
     * 声明切入点表达式,一般在该方法中不再添加其他代码。
     * 使用@Pointcut来声明切入点表达式。
     * 后面的通知直接使用方法名来引用当前的切入点表达式。
     * 后面表达式的方法就是目标方法
     */
    @Pointcut("execution(* com.xxx.aop.HelloWorld.* (..))")
    public void declareJoinPointExpression() {}

    /**
     *前置通知,在目标方法开始之前执行。
     *@Before("execution(*)")这样写可以指定特定的方法比如(public void com.xxx.aop.HelloWorld.print())。
      * @param joinpoint
      */
     @Before("declareJoinPointExpression()")
    public void printBefore(){
        System.out.println("执行前CurrentTime: "+System.currentTimeMillis());
    }
     /**
      *前置通知,在目标方法开始之后执行。
      *@after("execution(*)")这样写可以指定特定的方法比如(public void com.xxx.aop.HelloWorld.print())。
       * @param joinpoint
       */
      @After("declareJoinPointExpression()")
     public void printAfter(){
        System.out.println("执行后CurrentTime: "+System.currentTimeMillis());
    }
}

Test(测试类)

package com.xxx.aop;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
 *@description
 *@author create by xiaoxsen
 *@date   2017年8月14日---下午2:00:18
 */
public class Test {
  public static void main(String[] args) {
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    HelloWorld h = (HelloWorld) context.getBean(HelloWorld.class);
    h.print();
  }
}

xml配置文件(applicationContext.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:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.0.xsd"
        >
    <!-- 配置自动扫描包 -->
    <context:component-scan base-package="com.xxx.aop"></context:component-scan>
    <!-- 使AspectJ注解起作用:自动为匹配的类生产代理对象 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

运行结果:

执行前CurrentTime: 1502703074952
helloworld
执行后CurrentTime: 1502703074970

注意:基于注解时需要在xml文件中添加如下代码:

 <context:component-scan base-package="com.xxx.aop"></context:component-scan>
    <!-- 使AspectJ注解起作用:自动为匹配的类生产代理对象 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

然后aspectjweaver.jar需要更新到最近的版本,不然会因为jdk版本高,aspectjweaver.jar不是最近的造成异常。
五、总结
  Spring中AOP代理由Spring的IOC容器负责生成、管理,其依赖关系也由IOC容器负责管理。因此,AOP代理可以直接使用容器中的其它bean实例作为目标,这种关系可由IOC容器的依赖注入提供。Spring创建代理的规则为:
  1、默认使用Java动态代理来创建AOP代理,这样就可以为任何接口实例创建代理了
  2、当需要代理的类不是代理接口的时候,Spring会切换为使用CGLIB代理,也可强制使用CGLIB,在xml中配置就好。
通过上面的示例发现SpringAOP编程我们需要处理的就是:
  1、定义普通业务组件(比如HelloWorld类)
  2、定义切入点,一个切入点可能横切多个业务组件(比如Logger类)
  3、定义增强处理,增强处理就是在AOP框架为普通业务组件织入的处理动作

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值