jdk动态代理简单实现springAOP原理 在近期学习了spring框架,在使用spring官方提供的jar包和配置文件进行了实现,对它内部的实现方法进行了一些了解,并想在此记录并分享出来。这也是我第一次发博客,在排版和内容上会有一些不足,如有错误和建议欢迎大家在下方评论指出!!!
简单介绍一下AOP的相关概念
1、AOP和OOP的关系 AOP(Aspect-OrientedProgramming,面向切面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善。 2、相关术语 (1)Aspect(切面):通常是一个类,里面可以定义切入点和通知 (2)JointPoint(连接点):程序执行过程中明确的点,一般是方法的调用 (3)Advice(通知):AOP在特定的切入点上执行的增强处理,有before,after,afterReturning,afterThrowing,around (4)Pointcut(切入点):就是带有通知的连接点,在程序中主要体现为书写切入点表达式 (5)AOP代理:AOP框架创建的对象,代理就是目标对象的加强。Spring中的AOP代理可以使JDK动态代理,也可以是CGLIB代理,前者基于接口,后者基于子类
个人理解
相关概念都是度娘上的标准答案。简单来说,就目的而言这个技术就是为了一步减低程序代码间的耦合度,而我们在日常开发中以肯定知到“开闭原则”------对扩展是开放的,对修改是关闭的(这里的修改是指对源码的修改)。AOP可以实现对一个类或一段代码片段不做修改而添加一些给定的功能。
接下来我们便用jdk动态代理来模拟实现一下aop的基础实现过程
这里使用一个例子给大家参考
当前我们已经完成了一个功能的实现过程
public class Test {
public void a(){
//这里就以一条输出语句作为具体的功能
System.out.println("功能实现的过程");
}
}
后期我们有一个需求:获取功能实现的所需时间,我们的第一反应是在源码的基础上做修改 ` public class JcImpl{ public void a(){ //获取代码执行之前的系统毫秒值 long L1=System.currentTimeMillis();
System.out.println("功能实现的过程");
//获取代码执行完之后的系统毫秒值
long L2=System.currentTimeMillis();
//将L2减去L1获取运行时间
long L3=L2-L1;
System.out.println("代码运行时间为"+L3+"毫秒!!!");
}
} ` 这样做虽然能完成对功能的实现,但在软件开发过程中并不推荐这样做,而且对一个已经完成的软件系统源码做修改是一个大忌。接下来我们用动态代理模式对此需求进行实现。
动态代理实现
这里创建了两个包,一个接口四个类
1.先定义一个基础类的接口
package com.test.util;
public interface Jc {
//定义一个接口规范
void a();
}
2.实现类实现接口定义的方法
package com.test.util;
public class JcImpl implements Jc {
@Override
public void a() {
System.out.println("功能实现的过程 ");
}
}
3.把获取系统时间的方法单独写到一个类中
package com.test.util;
public class TimeUtil {
//将系统当前时间的毫秒值返回
public long getTime() {
long time=System.currentTimeMillis();
return time;
}
}
4.编写一个代理类,通过构造方法将获取时间的类织入到基础类 ` package com.test.util; //用到的反射的包 import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method;
//需要实现InvocationHandler接口中的invoke()方法 public class JcImplProxy implements InvocationHandler {
//基础功能对象
private Object obj;
//附加功能对象
private TimeUtil tu;
//定义构造方法将原功能和要附加的功能织入到此工具类中
public JcImplProxy(Object obj,TimeUtil tu) {
this.obj=obj;
this.tu=tu;
}
//通过代理实例上的方法调用并返回结果
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long L1=tu.getTime();
Object newObj=method.invoke(obj, args);
long L2=tu.getTime();
long L3=L2-L1;
System.out.println("代码运行时间为"+L3+"毫秒!!!");
return newObj;
}
` 至此基本功能组件都以编写完成,现在编写一个测试程序
` package com.test.proxytest;
import java.lang.reflect.Proxy; import com.test.util.Jc; import com.test.util.JcImpl; import com.test.util.JcImplProxy; import com.test.util.TimeUtil;
public class ProxyJunit {
public static void main(String[] args) {
//基础类
Jc obj=new JcImpl();
//附加功能
TimeUtil tu=new TimeUtil();
//通过代理类的构造方法将附加类织入到基础类中
JcImplProxy js=new JcImplProxy(obj, tu);
//有三个参数。第一个为基础类的类加载器,第二个为基础类的接口集合,第三个为代理类对象
Jc newjs=(Jc)Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(),js);
newjs.a();
}
}
`
以下就是运行结果截图,我们并没有对程序的源码进行修改,实现了业务需求。当然我们这里只用了一条输出语句作为具体功能的实现,而现在的cup运行速度是非常快的,所以只用了0毫秒的时间便完成了功能的实现。
总结
以上用jdk的动态代理简单的实现了一下aop基础的实现原理。当然我写的很简单,都是基础的东西,如大家有其他看法请在评论区指出。