Spring AOP简介及简单实例

一、SpringAOP 简介

1.AOP思想:

AOP即面向切面编程,可以说是OOP的补充和完善。它利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为"Aspect",即切面。
           所谓"切面",简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。

2.AOP概念:

1)AOP把软件系统分为两个部分:核心关注点和横切关注点

业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。
横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处基本相似,比如设置页面编码、权限认证、日志、事务。

AOP的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。

3.AOP使用

AOP编程其实是很简单的事情,纵观AOP编程,程序员只需要参与三个部分:

  • 1)定义普通业务组件
  • 2)定义切入点,一个切入点可能横切多个业务组件
  • 3)定义增强处理,增强处理就是在AOP框架为普通业务组件织入的处理动作

所以进行AOP编程的关键就是定义切入点(在哪里要添加方法)定义增强处理(要添加的方法),一旦定义了合适的切入点和增强处理,AOP框架将自动生成AOP代理,即:代理对象的方法=增强处理+被代理对象的方法

4.AOP概念:

横切关注点:对那些方法进行拦截,拦截后怎么处理,类似这些的关注点
切面(次要业务):是对横向关注点的抽象<aop:aspect>
连接点(所有可能进行切面操作的方法即类中的所有方法):被拦截到的点,因为Spring只支持方法类型的连接点不能操作属性和构造方法,所以在Spring中连接点指的就是被拦截到的方法,实际上连接点还可以是字段或者构造器
切入点(具体拦截到的方法):对连接点进行拦截的定义<aop:pointer>
通知:所谓通知指的就是指拦截到连接点之后要执行的代码,通知分为前置、后置、异常、最终、环绕通知五类
目标对象:代理的目标对象
织入(weave):(在原有的方法织入一个新的方法形成一个大方法)将切面应用到目标对象并导致代理对象创建的过程
    将切面的通知方法织入到切点方法的过程

5.Spring 对AOP的支持:

Spring中AOP代理由Spring的IOC容器负责生成、管理,其依赖关系也由IOC容器负责管理。因此,AOP代理可以直接使用容器中的其它bean实例作为目标,这种关系可由IOC容器的依赖注入提供。

   <aop:config>
            <aop:aspect id="time" ref="timeHandler"><>
                <aop:pointcut id="addAllMethod" expression="execution(* com.xrq.aop.HelloWorld.*(..))" />
                <aop:before method="printTime" pointcut-ref="addAllMethod" />
                <aop:after method="printTime" pointcut-ref="addAllMethod" />
            </aop:aspect>
   </aop:config>

二、SringAOP简单例子--方法执行前打印当前时间

1.pom.xml

<!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>5.0.8.RELEASE</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.0.8.RELEASE</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.7.2</version>
    </dependency>

2.业务逻辑

核心关注点(主要业务--打印Hello World!)

//接口
package org.lanqiao.aop;

public interface Hello {
      void print();
}

//实现类
package org.lanqiao.aop;

public class HelloImpl implements Hello {
    public void print() {
        System.out.println("Hello World!");
    }
}

横切关注点(次要业务--打印当前时间) 

package org.lanqiao.aop;

public interface TimeAOP {
    void printTime();
}



package org.lanqiao.aop;


import java.text.SimpleDateFormat;
import java.util.Date;

public class TimeAOPImpl implements TimeAOP {
    @Override
    public void printTime() {
        long currentTime = System.currentTimeMillis();
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒");
        Date date = new Date(currentTime);
        System.out.println(formatter.format(date));
    }
}

3.Spring配置文件aop.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <bean id="hello" class="org.lanqiao.aop.HelloImpl"/>
    <bean id="timeHander" class="org.lanqiao.aop.TimeAOPImpl"/>

    <aop:config><!--横切关注点,对哪些方法进行拦截,拦截后怎么处理-->
        <aop:aspect id="timeAspect" ref="timeHander"><!--定义切面 若有多个切面可通过执行顺序 order="1"等控制顺序或者上下文顺序   -->
            <aop:pointcut id="helloPointcut" expression="execution(* org.lanqiao.aop.Hello.*(..))"/><!--定义切入点-->
            <aop:before method="printTime" pointcut-ref="helloPointcut"/><!--将通知织入到切入点-->
            <!--<aop:around method="printTime" pointcut-ref="helloPointcut"/>-->
        </aop:aspect>
    </aop:config>

</beans>

常见切入点表达式的例子:

  • 任意公共方法的执行:

    execution(public * *(..))
    
  • 任何一个以“set”开始的方法的执行:

    execution(* set*(..))
    
  • AccountService 接口的任意方法的执行:

    execution(* com.xyz.service.AccountService.*(..))
    
  • 定义在service包里的任意方法的执行:

    execution(* com.xyz.service.*.*(..))
    
  • 定义在service包或者子包里的任意类的任意方法的执行:

    execution(* com.xyz.service..*.*(..))

4.测试 

package org.lanqiao;


import org.junit.Test;
import org.lanqiao.aop.Hello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class HelloTest
{
    @Test
    public void testPrint()
    {
        ApplicationContext ctx =
                new ClassPathXmlApplicationContext("aop.xml");
        Hello hello = (Hello)ctx.getBean("hello");
        hello.print();
    }
}

5.输出结果

 

相互学习,共同指教!

猜你喜欢

转载自blog.csdn.net/Bruce_Up/article/details/83097273