在学习Spring的时候,我们知道Spring主要有两大思想,一个是IOC,另一个就是AOP,对于IOC,依赖注入就不用多说了,而对于Spring的核心AOP来说,我们不但要知道怎么通过AOP来满足的我们的功能,我们更需要学习的是其底层是怎么样的一个原理,而AOP的原理就是java的动态代理机制,所以本篇随笔就是对java的动态机制进行一个回顾。
动态代理有两种方式:
1、jdk动态代理是由java内部的反射机制来实现的
2、cglib动态代理底层则是借助asm来实现的。
一、JDK动态代理,创建的效率高
jdk动态代理是jdk原生就支持的一种代理方式,它的实现原理,就是通过让target类和代理类实现同一接口,代理类持有target对象,来达到方法拦截的作用,这样通过接口的方式有两个弊端,一个是必须保证target类有接口,第二个是如果想要对target类的方法进行代理拦截,那么就要保证这些方法都要在接口中声明,实现上略微有点限制。
在java的动态代理机制中,有两个重要的类或接口,一个是 InvocationHandler(Interface)、另一个则是 Proxy(Class),这一个类和接口是实现我们动态代理所必须用到的
每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用。我们来看看InvocationHandler这个接口的唯一一个方法 invoke 方法:
Object invoke(Object proxy, Method method, Object[] args) throws Throwable
我们看到这个方法一共接受三个参数,那么这三个参数分别代表什么呢?
Object invoke(Object proxy, Method method, Object[] args) throws Throwable
proxy: 指代我们所代理的那个真实对象
method: 指代的是我们所要调用真实对象的某个方法的Method对象
args: 指代的是调用真实对象某个方法时接受的参数
这样就定义了一个动态代理类
package service;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Temp implements InvocationHandler {
private Object object;
/**
* 生成代理类
* @return
*/
public Object getUser()
{
return Proxy.newProxyInstance(this.getClass().getClassLoader(),
object.getClass().getInterfaces(),this);
}
/**
*
* @param proxy 生成的代理类
* @param method 代理类的调用处理程序的方法对象
* @param args
* @return
* @throws Throwable
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result=method.invoke(object,args);
return result;
}
public void setObject(Object object) {
this.object = object;
}
}
在invoke里面可以写需要执行的逻辑
调用:
package test;
import service.Service;
import service.Serviceimpl;
import service.Temp;
public class Proxy_test {
public static void main(String[] args) {
Serviceimpl serviceimpl=new Serviceimpl();//新建一个实体类
Temp temp=new Temp(); //代理类
temp.setObject(serviceimpl); //传入实体
Service service=( Service)temp.getUser();//接口类接受收
service.add();//执行公有方法
}
}
二、cglib动态代理 ,执行的效率高
使用CGLIB即使代理类没有实现任何接口也可以实现动态代理功能
1、写被代理的类
/**
* @author 贺文杰
* 2018/8/1 15:45
*/
public class UserServiceImpl {
public String say(String name){
System.out.println(name);
return name;
}
}
2、写Cglb类
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* @author 贺文杰
* 2018/8/1 16:02
*/
public class CglibProxy implements MethodInterceptor {
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("执行前");
Object object= methodProxy.invokeSuper(o,objects);
System.out.println("执行后");
return null;
}
}
3、执行:
import net.sf.cglib.proxy.Enhancer;
/**
* @author 贺文杰
* 2018/8/1 16:01
*/
public class Main {
public static void main(String[] args) {
CglibProxy proxy = new CglibProxy();
Enhancer enhancer = new Enhancer();
//给单独一个类设置超类
enhancer.setSuperclass(UserServiceImpl.class);
//设置回调
enhancer.setCallback(proxy);
UserServiceImpl userService=(UserServiceImpl) enhancer.create();
String string=userService.say("贺文杰");
System.out.println(string);
}
}