在Java中有多种动态代理技术,如JDK、CGLIB、Javassist、ASM,其中最常用的动态代理技术是JDK和CGLIB。

1、JDK的动态代理

JDK动态代理是java.lang.reflect.*包提供的方法,必须要借助一个接口才能产生代理对象,对于使用业务接口的类,Spring默认使用JDK动态代理实现AOP。
代码示例如下:
创建dao包,并创建StuDao接口和StuDaoImpl实现类,
StuDao接口

public interface StuDao {
public void add();
public void find();
public void update();
public void delete();
}

StuDaoImpl实现类

public class StuDaoImpl implements StuDao {
@Override
public void add() {
System.out.println("添加学生");
} @Override
public void find() {
System.out.println("查询学生");
} @Override
public void update() {
System.out.println("修改学生");
} @Override
public void delete() {
System.out.println("删除学生");
}
}

创建aspect包,并创建切面类MyAspect,该类中可以定义多个通知,即增强处理的方法,示例代码如下:

public class MyAspect {
public void check(){
System.out.println("模拟权限控制");
}
public void except(){
System.out.println("模拟异常处理");
}
public void log(){
System.out.println("模拟日志记录");
}
public void monitor(){
System.out.println("模拟性能检测");
}
}

创建proxy包,并创建代理类MyJdkProxy,在JDK动态代理中代理类必须实现java.lang.reflect.InvocationHandler接口,并编写代理方法,在代理方法中需要通过Proxy实现动态代理。示例代码如下:

package com.aop.proxy;

import com.aop.aspect.MyAspect;
import com.aop.dao.StuDao;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; public class MyJdkProxy implements InvocationHandler { //声明目标类接口对象(真实对象)
private StuDao stuDao; public MyJdkProxy(StuDao stuDao){
this.stuDao = stuDao;
} //创建代理的方法,建立代理对象和真实对象的代理关系,返回代理对象
public Object createProxy(){
//1.类加载器
ClassLoader cld = MyJdkProxy.class.getClassLoader();
//2.被代理对象实现的所有接口
Class[] clazz = stuDao.getClass().getInterfaces();
return Proxy.newProxyInstance(cld,clazz,this);
} /**
* 代理的逻辑方法,所有动态代理类的方法调用都交给该方法处理
* @param proxy 被代理对象
* @param method 要执行的方法
* @param args 执行方法时需要的参数
* @return 返回代理结果
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//创建一个切面
MyAspect myAspect = new MyAspect();
//前增强
myAspect.check();
myAspect.except();
//在目标类上调用方法并传入参数,相当于调用stuDao中的方法
Object obj = method.invoke(stuDao,args);
//后增强
myAspect.log();
myAspect.monitor();
return obj;
}
}

创建测试类

@Test
public void testStu(){
//创建目标对象
StuDao stuDao = new StuDaoImpl();
//创建代理对象
MyJdkProxy myJdkProxy = new MyJdkProxy(stuDao);
//从代理对象中获取增强后的目标对象
//该对象是一个被代理的对象,它会进入代理的逻辑方法invoke中
StuDao stuDaoProxy = (StuDao) myJdkProxy.createProxy();
//执行方法
stuDaoProxy.add();
System.out.println("==================");
stuDaoProxy.update();
System.out.println("==================");
stuDaoProxy.delete();
}

运行结果

2、CGLIB的动态代理

JDK动态代理必须提供接口才能使用,对于没有提供接口的类,只能采用CGLIB动态代理。CGLIB采用非常底层的字节码技术,对指定的目标类生产一个子类,并对子类进行增强。在Spring Core 包中已经集成了CGLIB所需要的jar包,无需另外引入jar包。
示例代码如下:
创建目标类TestDao

public class TestDao {
public void save(){
System.out.println("保存方法");
}
public void modify(){
System.out.println("修改方法");
}
public void delete(){
System.out.println("删除方法");
}
}

创建切面类MyAspect,并在该类中定义多个通知

public class MyAspect {
public void check(){
System.out.println("模拟权限控制");
}
public void except(){
System.out.println("模拟异常处理");
}
public void log(){
System.out.println("模拟日志记录");
}
public void monitor(){
System.out.println("模拟性能检测");
}
}

创建代理类MyCglibProxy,并实现MethodInterceptor接口

package com.aop.proxy;

import com.aop.aspect.MyAspect;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method; public class MyCglibProxy implements MethodInterceptor { /**
* 创建代理的方法,生成CGLIB代理对象
* @param target 目标对象,需要增强的对象
* @return 返回目标对象的CGLIB代理对象
*/
public Object createProxy(Object target){
//创建一个动态类对象,即增强类对象
Enhancer enhancer = new Enhancer();
//设置其父类
enhancer.setSuperclass(target.getClass());
//确定代理逻辑对象为当前对象
enhancer.setCallback(this);
return enhancer.create();
} /**
* 该方法会在程序执行目标方法时调用
* @param proxy 是CGLIB根据指定父类生成的代理对象
* @param method 是拦截方法
* @param args 拦截方法的参数数组
* @param methodProxy 方法的代理对象,用于执行父类的方法
* @return 返回代理结果
* @throws Throwable
*/
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
//创建一个切面
MyAspect myAspect = new MyAspect();
//前置增强
myAspect.check();
//目标方法执行,返回执行结果
Object obj = methodProxy.invokeSuper(proxy,args);
//后置增强
myAspect.log();
return obj;
}
}

创建测试类

@Test
public void test(){
//创建目标对象
TestDao testDao = new TestDao();
//创建代理对象
MyCglibProxy myCglibProxy = new MyCglibProxy();
//获取增强后的目标对象
TestDao testDaoAdvice = (TestDao) myCglibProxy.createProxy(testDao);
//执行方法
testDaoAdvice.save();
System.out.println("==================");
testDaoAdvice.modify();
System.out.println("==================");
testDaoAdvice.delete();
}

运行结果

3、动态代理注意事项

(1)程序中应优先对接口创建代理,便于程序解耦维护;

(2)使用final关键字修饰的方法不能被代理,因为无法覆盖

  • JDK动态代理,是针对接口生成子类,接口中方法不能使用final修饰
  • CGLIB是针对目标类生成子类,因此类或方法不能使用final修饰

(3)Spring只支持方法连接点,不提供属性连接点

Spring框架学习06——AOP底层实现原理的更多相关文章

  1. Spring框架IOC和AOP的实现原理(概念)

    IoC(Inversion of Control) (1). IoC(Inversion of Control)是指容器控制程序对象之间的关系,而不是传统实现中,由程序代码直接操控.控制权由应用代码中 ...

  2. Spring框架IOC和AOP的实现原理

    IoC(Inversion of Control) (1). IoC(Inversion of Control)是指容器控制程序对象之间的关系,而不是传统实现中,由程序代码直接操控.控制权由应用代码中 ...

  3. Spring框架学习05——AOP相关术语详解

    1.Spring AOP 的基本概述 AOP(Aspect Oriented Programing)面向切面编程,AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码(性能监视.事务管理.安全检查 ...

  4. spring框架学习(三)——AOP( 面向切面编程)

    AOP 即 Aspect Oriented Program 面向切面编程 首先,在面向切面编程的思想里面,把功能分为核心业务功能,和周边功能. 所谓的核心业务,比如登陆,增加数据,删除数据都叫核心业务 ...

  5. spring框架学习(六)AOP

    AOP(Aspect-OrientedProgramming)面向方面编程,与OOP完全不同,使用AOP编程系统被分为方面或关注点,而不是OOP中的对象. AOP的引入 在OOP面向对象的使用中,无可 ...

  6. Spring框架学习总结(上)

    目录 1.Spring的概述 2.Spring的入门(IOC) 3.Spring的工厂类 4.Spring的配置 5.Spring的属性注入 6.Spring的分模块开发的配置 @ 1.Spring的 ...

  7. Spring框架学习笔记(1)

    Spring 框架学习笔记(1) 一.简介 Rod Johnson(spring之父) Spring是分层的Java SE/EE应用 full-stack(服务端的全栈)轻量级(跟EJB比)开源框架, ...

  8. Spring框架学习一

    Spring框架学习,转自http://blog.csdn.net/lishuangzhe7047/article/details/20740209 Spring框架学习(一) 1.什么是Spring ...

  9. Spring框架学习1

    AnonymouL 兴之所至,心之所安;尽其在我,顺其自然 新随笔 管理   Spring框架学习(一)   阅读目录 一. spring概述 核心容器: Spring 上下文: Spring AOP ...

随机推荐

  1. Executor线程池的简单使用

    我们都知道创建一个线程可以继承Thread类或者实现Runnable接口,实际Thread类就是实现了Runnable接口. 到今天才明白后端线程的作用:我们可以开启线程去执行一些比较耗时的操作,类似 ...

  2. linux 中的 open() read() write() close() 函数

    1. open()函数 功能描述:用于打开或创建文件,在打开或创建文件时可以指定文件的属性及用户的权限等各种参数. 所需头文件:#include <sys/types.h>,#includ ...

  3. MFC创建线程示例

    MFC创建线程示例 AfxBeginThread() 创建现场的方法是AfxBeginThread()函数. 在[.CPP]文件定义一个全局变量,决定什么时候退出这个线程. BOOL g_bWillE ...

  4. python3之协程

    1.协程的概念 协程,又称微线程,纤程.英文名Coroutine. 线程是系统级别的它们由操作系统调度,而协程则是程序级别的由程序根据需要自己调度.在一个线程中会有很多函数,我们把这些函数称为子程序, ...

  5. c# webbrowser控件内核版本强制修改

    int BrowserVer, RegVal; // get the installed IE version using (WebBrowser Wb = new WebBrowser()) Bro ...

  6. MVC自定义视图引擎地址

    先看结构 1.RouteConfig 文件(注意顺序) public static void RegisterRoutes(RouteCollection routes) { routes.Ignor ...

  7. 用python查看windows事件日志的方法(待后续研究)

    #coding=utf8 import copy import ctypes from ctypes import byref, POINTER, cast, c_uint64, c_ulong, c ...

  8. Win10 + VS2017 15.5.6 环境下解决 Python 3.6 环境无法刷新DB的问题

    作为宇宙第一IDE,VS2017对Python的支持还算可以,虽然和PyCharm等Python专用IDE相比还有些差距,但是经过后续的更新升级,我相信VS2017将越来越完善.由于本人一直都是使用V ...

  9. sum行列合计

    select sum(decode(cplb,'3',hj,0)) from lr_scsjdqdw t group by zcxmdm

  10. 020_秘钥管理服务器vault

    一. https://github.com/hashicorp/vault     #待研究