Spring的两大核心之一就是AOP,AOP:面向切面编程。在说原理之前,得先知道一些 AOP的专业术语。

AOP的专业术语

连接点(JoinPoint):增强执行的位置(增加代码的位置),Spring只支持方法;
切点(PointCut):具体的连接点;一般可能通过一个表达式来描述;
增强(Advice):也称为消息,指的是增加的额外的代码,Spring中,增强除了包含代码外,还包含位置信息;

Spring中一共有四种增强:

  • MethodBeforeAdvice:前置增强
  • MethodInterceptor:环绕增强
  • ThrowsAdvice:异常增强
  • AfterReturingAdvice:返回值增强

引介(Introduction):特殊的增强,动态为类增加方法
织入(Weaving):将增强加入到目标类的过程,织入分为三种时期

  • 编译器:AspectJ
  • 类加载
  • 运行期:jdk动态代理(实现接口),CGlib(子类,不能用final)

目标对象(Target):原始对象
代理对象(Proxy):加入了增强的对象,是生成的;
切面(Aspect):切点+增强

接下来我要说的就是在运行期间织入的两种实现方式

JDK动态代理(实现接口)

什么是代理模式呢?

代理模式有三个角色,分别是

  • 抽象角色:接口
  • 目标角色:实现类
  • 代理角色:实现接口(InvocationHandler),并引用目标角色

代理模式与装饰者模式的区别
类图(结构)基本一样,但目的不同,装饰模式的前提是已经所有的类,并进行组装;

而使用代理模式时,我们不能直接访问目标角色或没有权限访问时,可以使用代理模式

代理模式分为两种

  • 静态代理:需要为每个目标角色,创建一个对应的代理角色;类的数量会急剧膨胀
  • 动态代理:自动为每个目标角色生成对应的代理角色
  1. 接下来就是jdk动态代理的代码:

实现jdk动态代理的前提是所有的目标类都必须要基于一个统一的接口

创建统一的接口
[java] view plain copy
package com.dao;
/**
* 为目标类定义统一的接口SleepDao
* @author XuXQ
*
*/
public interface SleepDao {
  public void sleep();
}

定义目标对象
[java] view plain copy
package com.daoImpl;
import com.dao.SleepDao;
/**
* 目标类
* @author XuXQ
*
*/
public class SleepDaoImpl implements SleepDao {

@Override
public void sleep() {
System.out.println("本大人要睡觉了");
}

}

创建代理角色

[java] view plain copy
package com.handler;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* 创建的类得需要实现InvocationHandler,并重写invoke()方法
* InvocationHandler 是代理实例的调用处理程序 实现的接口
* 即:MyInvocationHandler 是代理实例的调用处理程序
* @author XuXQ
*
*/
public class MyInvoctionHandler implements InvocationHandler {
Object object=null;//目标对象

public MyInvoctionHandler(Object object) {
super();
this.object = object;
}

/**
* proxy=代理对象
* method=被调用方法的方法名
* args=被调用方法的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws

Throwable {
System.out.println("睡觉前要脱衣服啊");
Object obj=method.invoke(object, args);//obj为目标对象调用方法的返回


System.out.println("睡着了当然得做个美梦啊");
return obj;
}

}

[java] view plain copy
编写测试用例
[java] view plain copy
package com.handler;
[java] view plain copy
import static org.junit.Assert.*;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import com.dao.SleepDao;
import com.daoImpl.SleepDaoImpl;
public class Test1 {
@Before
public void setUp() throws Exception {
}
@After
public void tearDown() throws Exception {
}
@Test
public void test() {
//目标类必须基于统一的接口
SleepDao s=new SleepDaoImpl();
ClassLoader classLoader=s.getClass().getClassLoader();
MyInvoctionHandler myInvoctionHandler=new MyInvoctionHandler(s);

//Proxy为InvocationHandler实现类动态创建一个符合某一接口的代理实例

SleepDao sd=(SleepDao) Proxy.newProxyInstance(classLoader,

s.getClass().getInterfaces(), myInvoctionHandler);

//相当于调用代理角色的Invoke()
sd.sleep();
}

}

结果:

由结果可以看到成功的将增强织入到了目标对象中了

此处使用到了jdk的动态代理,invocationHandler,proxy,以及classloader在另外两篇文章有详解

InvocationHandler和Proxy(Class)的动态代理机制详解

http://www.cnblogs.com/shoshana-kong/p/9041485.html

ClassLoader工作机制

http://www.cnblogs.com/shoshana-kong/p/9042013.html

2.CGlib代理

[java] view plain copy
package com.cglibproxy;
/**
* 和JDK动态代理不同,不需要创建统一的接口
* @author XuXQ
*
*/
public class Base {
public void sleep(){
System.out.println("本大少要睡觉啦");
}
}<strong>
</strong>

创建cglib的代理对象
[java] view plain copy
package com.cglibproxy;

import java.lang.reflect.Method;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

//用来生成代理对象
public class CglibProxy implements MethodInterceptor {

public Object getProxy(Object object){
Enhancer e=new Enhancer();//创建代理对象类
e.setSuperclass(object.getClass());//声明代理对象的父类是谁(是目标

对象)
e.setCallback(this);//设置回调函数,即调用intercept()
return e.create();//返回创建的代理对象
}
/**
<span style="white-space:pre;"> </span> * proxy=代理对象,也是目标对象的子类
<span style="white-space:pre;"> </span> * args=方法参数
<span style="white-space:pre;"> </span> */
@Override
public Object intercept(Object proxy, Method method, Object[] args,

MethodProxy arg3) throws Throwable {
System.out.println("你个大懒猪,竟然睡觉前不脱衣服,嫌弃o");
Object object=arg3.invokeSuper(proxy, args);
System.out.println("起床啦,要不然得迟到了哦");
return null;
}

}

编写测试用例
[java] view plain copy
package com.cglibproxy;

import static org.junit.Assert.*;

import org.junit.After;
import org.junit.Before;

public class Test {

@Before
public void setUp() throws Exception {
}

@After
public void tearDown() throws Exception {
}

@org.junit.Test
public void test() {
CglibProxy proxy=new CglibProxy();
Base base=(Base) proxy.getProxy(new Base());
base.sleep();
}

}

结果:

由结果同样可以看到成功的将增强织入到了目标对象中了

此处涉及cglib相关知识

Cglib及其基本使用

http://www.cnblogs.com/shoshana-kong/p/9041834.html

总结
当然我们以后写代码都是基于Aspect,直接写注解的,当然这并不代表这我们不需要知
道AOP

底层的实现原理,至于注解用的是哪种实现方式,使用配置来解决的,这里就不详解了

最新文章

  1. Thymeleaf3.0内容
  2. 给li设置float浮动属性之后,无法撑开外层ul的问题。
  3. centos 6.5 apache配置web应用&amp;防火墙设置(入门级)
  4. 【POJ】1284 Primitive Roots
  5. C#创建桌面快捷方式 和 开机启动
  6. PLSQL_性能优化系列16_Oracle Tuning Analyze优化分析
  7. 我理解的C++虚函数表
  8. Selenium2Library系列 keywords 之 _SelectElementKeywords 之 page_should_contain_list(self, locator, message=&#39;&#39;, loglevel=&#39;INFO&#39;)
  9. Cocos2d-x v3.3 lua绑定c++类方法总结
  10. 2个2D向量计算交点的夹角和补角
  11. Debian 安装 vmware-tools 手记
  12. ARM v7汇编与相关练习
  13. 原生sql整理
  14. OneNote中添加代码问题
  15. IdentityServer4【Topic】之登陆注册
  16. ActiveMQ_5死信队列
  17. Android Studio导入系统 jar包,编译时优先于查找系统SDK
  18. 心情烦闷annoying,贴几个图!唉!annoying
  19. NPOI+反射+自定义特性实现上传excel转List及验证
  20. appium+python自动化33-解锁九宫格(TouchAction)

热门文章

  1. .net 表达式返回值和等号赋值的区别
  2. QFileSystemModel中通过flags函数反应代码的层级思考
  3. msfvenom生成各类Payload命令
  4. 剑指Offer 58. 对称的二叉树 (二叉树)
  5. 【EMV L2】SDA静态数据认证处理流程
  6. PHP输出缓存ob系列函数详解
  7. 国内优秀MVC开源框架jfinal简介
  8. python: ImportError:DLL load failed 解决方法。
  9. CentOS7下安装Python3及Pip3并保留Python2
  10. oracle存储结构