Spring面向切面编制程序初探

作者: 编程技术  发布:2019-10-07

通知

文告定义了断面是如何以及何时使用切面。Spring切面能够选拔5种等级次序的照应:

  1. Before: 在情势被调用以前布告
  2. After: 在措施成功以往调用文告,无论方式是或不是实行成功
  3. After-returning: 在点子成功施行之后调用文告
  4. After-throwing: 在艺术抛出非常之后调用公告
  5. Around: 布告包裹了被打招呼的法子,在被打招呼的办法调用以前和调用之后奉行自定义行为

一、术语解释

连接点

连接点是在利用试行进度中 能够插入切面包车型大巴八个点,这些点能够是调用方法时,抛出卓殊时,乃至是修改三个字段时。切面代码能够利用这个点插入到应用的通常流程之中,并加多新的一举一动。

1. 通知(Advice)

  • 松开文告(before)在对象措施被调用此前调用布告成效
  • 前置文告(After)在对象措施成功现在调用布告
  • 归来公告(After-returning)在目的措施成功实行之后调用公告
  • 特别公告(After-throwing)在对象措施抛出格外后调用文告
  • 围绕文告(Around)布告包裹了被打招呼的法子,在被打招呼的办法调用在此之前和调用之后实践自定义的作为

切点

切点即为切面切入的 位置

2. 连接点(Join point)

引入

引入允许大家向现存的类增添新的不二秘诀和质量,指标是在没有需求修改现存类的景况下,让他俩具备新的表现和情景。

连接点是在选取推行进程中能够插入切面包车型客车三个点。那一点能够是调用方法时、抛出特别时、以致修改多个字段时。切面代码能够选择这么些点插入到利用的平日流程中,并增多新的行为。

织入

织入是将切面应用到对象对象来创建新的代办对象的 过程

3. 切点(Pointcut)

非环绕型公告

<!--两个可爱的JavaBean--><bean /><bean /><!--切面声明开始--> <aop:config> <!--切面部分开始,如你所见一个Robot的类正在被定义成为一个切面--> <aop:aspect ref="robot"> <!--定义切点--> <aop:pointcut expression="execution(* entity.Person.sayHello" /> <!--定义切点:如果通知需要传参--> <aop:pointcut expression="execution(* entity.Person.sayWord and args" /> <!--前置通知--> <aop:before method="beforeSayHello" pointcut-ref="sayHello" /> <!--前置通知:通知内引用上文的thoughts参数--> <aop:before method="beforeSayHello" pointcut-ref="sayHello" arg-names="thoughts"/> <!--后置通知--> <aop:after method="afterSayHello" pointcut-ref="sayHello" /> <!--方法执行成功后的通知--> <aop:after-returning method="finishSayHello" pointcut-ref="sayHello" /> <!--执行异常时的通知--> <aop:after-throwing method="exceptionThrows" pointcut-ref="sayHello" /> </aop:aspect> </aop:config>

简易测量检验一下:

ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); Person tom =  ctx.getBean; tom.sayHello();

切点定义了"何地“。切点的定义会合营通告所要织入的贰个或三个连接点。平常采纳显著的点和章程名称,或是利用正则表明式定义所相配的类或方式名称来钦命那一个切点。

环绕型通告

<aop:config> <aop:aspect ref="robot"> <aop:pointcut expression="execution(* entity.Person.sayHello" /> <!--环绕通知--> <aop:around method="watchYouSayHello" pointcut-ref="sayHello" /> </aop:aspect></aop:config>

咱俩来看一下JavaBean中是怎么着注脚那些措施的:

//AOP环绕通知public void watchYouSayHello(ProceedingJoinPoint joinPoint) { try { System.out.println("Before say hello!"); long start = System.currentTimeMillis(); //执行被通知的方法 joinPoint.proceed(); long end = System.currentTimeMillis(); System.out.println("Say hello finished!"); System.out.println("This project has run " + (end - start) + "ms!"); } catch (Throwable throwable) { throwable.printStackTrace(); }}

在main方法中施行后效果同上。

4. 切面(Aspect)

非环绕型通告

表明切面能够使我们免受在XML中配置AOP

@Aspectpublic class Robot { //声明切点 @Pointcut("execution(* entity.Person.sayHello //声明切点标识方法 public void sayHello() { } //通知前置调用 @Before("sayHello public void beforeSayHello() { System.out.println("before say hello"); } //通知后置调用 @After("sayHello public void afterSayHello() { System.out.println("after say hello"); } //方法执行成功后调用 @AfterReturning("sayHello public void finishSayHello() { System.out.println("say hello finished"); } //方法执行异常时调用 @AfterThrowing("sayHello public void exceptionThrows() { System.out.println("an exception was throwed"); } //AOP环绕通知 @Around("sayHello public void watchYouSayHello(ProceedingJoinPoint joinPoint) { try { System.out.println("before say hello"); long start = System.currentTimeMillis(); //执行被通知的方法 joinPoint.proceed(); long end = System.currentTimeMillis(); System.out.println("say hello finished"); System.out.println("this project has run " + (end - start) + "ms"); } catch (Throwable throwable) { throwable.printStackTrace(); } }}

唯独大家须要在XML中的beans根标签下额外界署部分事物

<?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: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.xsd"> <!--如果使用注解形式,请务必加上该配置--> <aop:aspectj-autoproxy/> <bean /> <bean /></beans>

断面是打招呼和切点的三结合。公告和切点共同定义了断面包车型大巴全体内容——它是怎么样,在哪天和哪个地方实现其他职能。

环绕型通告

@Aspectpublic class Robot { @Pointcut("execution(* entity.Person.sayHello public void sayHello() { } //AOP环绕通知 @Around("sayHello public void watchYouSayHello(ProceedingJoinPoint joinPoint) { try { System.out.println("before say hello"); long start = System.currentTimeMillis(); //执行被通知的方法 joinPoint.proceed(); long end = System.currentTimeMillis(); System.out.println("say hello finished"); System.out.println("this project has run " + (end - start) + "ms"); } catch (Throwable throwable) { throwable.printStackTrace(); } }}

5. 引入(Introducetion)

引入允许大家向现有的类增多新的措施或性质。

6. 织人(Weaving)

织入是把切面应用到对象对象并成立新的代理对象的进度。切面在钦赐的连接点被织入到对象对象中。在指标对象的扬言周期里有三个点能够织入。

  • 编译期:切面在目的类编写翻译时被织入。这种艺术须要特殊的编写翻译器。AspectJ的织入编写翻译器正是以这种情势织入切面包车型大巴。
  • 类加载期:切面在指标类加载到JVM时被织入。这种格局需求极其的类加载器,它可以在指标类被引进应用以前拉长该目的类的字节码。
  • 运营期:切面在利用运转的有个别时刻被织入。经常情状下,在织入切面时,AOP容器会为对象对象动态地创立二个代理对象。

二、实例

创建Student类,拥有eat()方法。

图片 1

目录结构

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.imcoke.chapter04</groupId>
    <artifactId>chapter04</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <spring.version>4.1.7.RELEASE</spring.version>
        <junit.version>4.12</junit.version>
        <aspectj.version>1.8.11</aspectj.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</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-test</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!--spring-context中存在着SpringAOP依赖,所以这里也可以不单独引入SpringAop-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>${aspectj.version}</version>
        </dependency>

    </dependencies>

</project>

package com.imcoke.chapter04.domain;

/**
 * @Author ccoke
 * @Description
 * @Date: 11:25 2017-12-20
 */
public interface People {
    void eat(String foodName);
}

package com.imcoke.chapter04.domain;

import org.springframework.stereotype.Component;

/**
 * @Author ccoke
 * @Description
 * @Date: 11:26 2017-12-20
 */
@Component
public class Student implements People {
    private  static final String name = "学生";
    public void eat(String foodName) {
        System.out.println(name + "吃了" + foodName);
    }
}

package com.imcoke.chapter04.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

/**
 * @Author ccoke
 * @Description
 * @Date: 11:42 2017-12-20
 */
@Configuration
@EnableAspectJAutoProxy //启用AspectJ自动代理
@ComponentScan(value = {"com.imcoke.chapter04"})
public class PeopleConfig {

}

package com.imcoke.chapter04;

import com.imcoke.chapter04.config.PeopleConfig;
import com.imcoke.chapter04.domain.People;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.junit.Test;

/**
 * @Author ccoke
 * @Description
 * @Date: 11:30 2017-12-20
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = PeopleConfig.class)
public class TestAOP {
    @Autowired
    private People people;
    @Test
    public void test(){
        people.eat("棒棒糖");
    }
}

1. 创立Aspect,对eat()进行督察

package com.imcoke.chapter04.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

/**
 * @Author ccoke
 * @Description
 * @Date: 13:57 2017-12-20
 */
@Aspect
@Component
public class Monitor {
    /*
    * AspectJ切点表达式
    * 返回值 方法所属类.方法(参数)
    * (..):任意参数
    * */
    @Pointcut("execution(* com.imcoke.chapter04.domain.People.*(..))") //定义切点,指定方法
    public void pointCut(){
    }

    @Before("pointCut()")
    public void doBefore(){
        System.out.println("吃之前不获取参数" );
    }

    @Before("pointCut()")
    public void doBefore(JoinPoint joinPoint){
        System.out.println("吃之前获取参数:" + joinPoint.getArgs()[0]);
    }

}

图片 2

运营结果

2. 运用环绕布告对eat()举办监察和控制

package com.imcoke.chapter04.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

/**
 * @Author ccoke
 * @Description
 * @Date: 13:57 2017-12-20
 */
@Aspect
@Component
public class Monitor {
    /*
    * AspectJ切点表达式
    * 返回值 方法所属类.方法(参数)
    * (..):任意参数
    * */
    @Pointcut("execution(* com.imcoke.chapter04.domain.People.*(..))") //定义切点,指定方法
    public void pointCut(){
    }

    @Around("pointCut()")
    public void doAround(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("吃之前获取参数:" + pjp.getArgs()[0]); //获取eat()执行之前的参数
        pjp.proceed(new String[]{"巧克力"});//这句表示执行方法,这里传入的新的参数替代之前的参数
        System.out.println("吃完了!");
    }

}

图片 3

运维结果

3. 自定义切点申明

图片 4

目录结构

package com.imcoke.chapter04.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @Author ccoke
 * @Description
 * @Date: 15:22 2017-12-20
 */
@Target(ElementType.METHOD) //注解运用于方法之上
@Retention(RetentionPolicy.RUNTIME) //运行时保留
public @interface MonitorAnnotation {
}

package com.imcoke.chapter04.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

/**
 * @Author ccoke
 * @Description
 * @Date: 13:57 2017-12-20
 */
@Aspect
@Component
public class Monitor {

    @Pointcut("@annotation(com.imcoke.chapter04.annotation.MonitorAnnotation)") //自定义注解
    public void pointCut(){
    }

    @Around("pointCut()")
    public void doAround(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("吃之前获取参数:" + pjp.getArgs()[0]); //获取eat()执行之前的参数
        pjp.proceed(new String[]{"巧克力"});//这句表示执行方法,这里传入的新的参数替代之前的参数
        System.out.println("吃完了!");
    }

}

package com.imcoke.chapter04.domain;

import com.imcoke.chapter04.annotation.MonitorAnnotation;
import org.springframework.stereotype.Component;

/**
 * @Author ccoke
 * @Description
 * @Date: 11:26 2017-12-20
 */
@Component
public class Student implements People {
    private  static final String name = "学生";
    @MonitorAnnotation //使用自定义注解
    public void eat(String foodName) {
        System.out.println(name + "吃了" + foodName);
    }
}

图片 5

运维结果

本文由贝博体育app发布于编程技术,转载请注明出处:Spring面向切面编制程序初探

关键词:

上一篇:路子设计算法初始认知
下一篇:没有了