[JAVA] Spring 框架学习总结(二)

前言

续上一节,继续学习 Spring 的一些概念和理论。

什么是 AOP

AOP,Aspect-Oriented Programming,面向切面编程。(是一种程序设计思想)

AOP:通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。

主要的功能是:日志记录,性能统计,安全控制,事务处理,异常处理等等,如下图

切面

AOP 实现方式

预编译

  • AspectJ

运行期动态代理(JDK动态代理、CGLib动态代理)

  • SpringAOP
  • JbossAOP

Spring 的 AOP 实现

  • 纯 Java 实现,无需特殊的编译莞城,不需要控制加载器层次
  • 目前只支持方法执行连接点
  • 侧重于提供一种 AOP 实现和 Spring IoC 容器之间的整合,用于帮助解决企业应用中的常见问题
  • Spring AOP 默认使用标准的 JavaSE 动态代理作为 AOP 代理,这使得任何接口(接口集)都可以被代理
  • Spring AOP 中可以使用 CGLib 代理

AOP 基本概念

工欲善其事,必先利其器。还是得继续学习这些基本概念

Aspect(切面)

切面,是对交叉业务逻辑的统称。

Joinpoint(连接点)

连接点,指切面可以织入到目标对象的位置(方法,属性等)。

Advice(通知)

通知,指切面的具体实现。

Pointcut(切入点)

切入点,指通知应用到哪些类的哪些方法或属性之上的规则。

Introduction(引入)

引入,指动态地给一个对象增加方法或属性的一种特殊的通知。

Weaving(织入)

织入,指将通知插入到目标对象。

Target(目标对象)

目标对象,指需要织入切面的对象。

Proxy(代理对象)

代理对象,指切面织入目标对象之后形成的对象。

Spring Advice 类型

Before Advice(前置通知)

类全名:org.springframework.aop.MethodBeforeAdvice

在方法调用之前,做处理。

  • 不能够改变返回值

  • 不能够改变目标方法的流程,也不能中断流程的处理过程(除非抛出异常)

After Returning Advice (返回后通知)

类全名:org.springframework.aop.AfterReturningAdvice

在方法调用之后,做处理。

  • 不能够改变返回值

  • 不能够改变目标方法的流程,也不能中断流程的处理过程(除非抛出异常)

MethodInterceptor (拦截器)

类全名:org.aopalliance.intercept.MethodInterceptor

在方法调用之前以及之后,做处理。

  • 可以改变返回值,也可以改变流程。

ThrowsAdvice (抛出异常后通知)

类全名:org.springframework.aop.ThrowsAdvice

在方法抛出异常后,做处理。

  • 当该通知处理完异常后,会简单地将异常再次抛出给目标调用方法。

AOP 实现

理论看太多,该实际操作实践一下

基于 AspectJ 语言的实现方式

先新建两个简单的类

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
package com.eliteams.quick4j.test.aopTest;

/**
* Created by ARNO on 2016/4/11/011.
* desc:
*/
public class A {
private static final String TAG = "A";

public void sayHello(){
System.out.println("I'm A");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.eliteams.quick4j.test.aopTest;

/**
* Created by ARNO on 2016/4/11/011.
* desc:
*/
public class B {
private static final String TAG = "B";

public void sayHello(){
System.out.println("I'm B");
}

}

接下来编写切面类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.eliteams.quick4j.test.aopTest;

/**
* Created by ARNO on 2016/4/11/011.
* desc:
*/
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class testAspect {
private static final String TAG = "testAspect";

@Pointcut("execution(* com.eliteams.quick4j.test.aopTest.*.say*())")
//创建"切入点",该"切入点"捕获了指定项目中相关类的方法("连接点")
public void testPointcut() { }

@AfterReturning(pointcut="testPointcut()")

//创建"通知",该"通知"绑定了具体的"切入点"
public void simpleAdvice() //"切入点"的执行代码,将被"目标对象"的"代理对象"执行
{
System.out.println("Hi qiji.tech");
}
}

编写配置文件

applicationContext.xml 的内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="GBK"?>
<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-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">

<aop:aspectj-autoproxy /> //织入"目标对象"和"切面"之间的关联关系

<bean id="a" class="com.eliteams.quick4j.test.aopTest.A" ></bean>
<bean id="b" class="com.eliteams.quick4j.test.aopTest.B" ></bean>

<bean id="testAspect" class="com.eliteams.quick4j.test.aopTest.testAspect" ></bean>
</beans>

编写测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.eliteams.quick4j.test.aopTest;

/**
* Created by ARNO on 2016/4/11/011.
* desc:
*/
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class testAspect {
private static final String TAG = "testAspect";

@Pointcut("execution(* com.eliteams.quick4j.test.aopTest.*.say*())")
//创建"切入点",该"切入点"捕获了指定项目中相关类的方法("连接点")
public void testPointcut() { }

@AfterReturning(pointcut="testPointcut()")

//创建"通知",该"通知"绑定了具体的"切入点"
public void simpleAdvice() //"切入点"的执行代码,将被"目标对象"的"代理对象"执行
{
System.out.println("Hi qiji.tech");
}
}

测试结果

运行结果如下:

1
2
3
4
I'm A
Hi qiji.tech
I'm B
Hi qiji.tech

后记

革命尚未成功,仍需努力

参考资料