动态代理的一些理解
关于java的动态代理,有jdk动态代理和cglib动态代理。jdk动态代理是基于接口实现的,而CGlib动态代理是基于继承思想实现的,它能用于没有接口的目标对象的代理,这是jdk动态代理所不具备的功能。如果目标对象有接口实现,选择JDK代理,如果没有接口实现选择Cglib代理
JDK动态代理
具体流程:
1.拿到被代理对象的引用,然后获取他的接口
2.JDK代理重新生成一个类,同时实现我们给的代理对象所实现的接口
3.把被代理对象的引用拿到了
4.重新动态生成一个class字节码
5.然后编译
代码很简单了,就是实现
java.lang.reflect.InvocationHandler接口,并使用
java.lang.reflect.Proxy.newProxyInstance()方法生成代理对象
关于jdk动态代理有下面一些总结:
Class getProxyClass(ClassLoader loader, Class... interfaces)
调用getProxyClass()会动态生成Proxy类的子类,并使用loader参数指定的类加载器加载;第二个参数interfaces指定该子类将要继承的接口,可以指定多个接口。
Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
1、ClassLoader loader:目标对象通过getClass方法获取类的所有信息后,调用getClassLoader()
方法来获取类加载器。获取类加载器后,可以通过这个类型的加载器,在程序运行时,将生成的代理类加载到JVM即Java虚拟机中,以便运行时需要!
2、Class[] interfaces:获取被代理类的所有接口信息,以便于生成的代理类可以具有代理类接口中的所有方法。注意这里表示该类可能是任意类 如果只是java类型 则可以用T表示
3、InvocationHandler h:我们使用动态代理是为了更好的扩展,比如在方法之前做什么,之后做什么等操作。这个时候这些公共的操作可以统一交给代理类去做。这个时候需要调用实现了InvocationHandler 类的一个实现方法。由于自身便实现了这个方法,所以将本类传递过去。
我们首先了一个简单地动态代理类,各部分的功能说明如下:
package com.xxxx.proxy;
import java.lang.annotation.Target;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* jdk动态代理类
*/
public class JdkHandler implements InvocationHandler {
//目标对象
private Object target;
//目标对象通过带参构造器传递进来
public JdkHandler(Object target){
this.target = target;
}
/**
*
* getProxy用来获取代理对象
* 获取代理对象
* @return
*
* 获取代理对象
* public static Object newProxyInstance(ClassLoader loader,Class[] interface,InvocationHandler h)
* 三个参数的说明
* loader:类加载器
* interface:接口数组
* InvocationHandler接口(传入InvocationHandler接口的实现类,一般本类就会实现InvocationHandler接口,这里是JdkHandler实现了这个接口)
*/
public Object getproxy(){
Object obj = Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(),this);
return obj;
}
/**
* 1 调用目标对象的方法
* 2 增强目标对象的行为
* @param proxy 调用该方法的代理实例(这里没有用到它)
* @param method 目标对象的方法
* @param args 目标对象的方法所需的参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object object = method.invoke(target,args);
return object;
}
}
有两个接口
Marry接口中的方法
package com.xxxx.proxy;
public interface Marry {
void toMarry();
}
Study中的接口方法
package com.xxxx.proxy;
public interface Study {
void university();
}
假如类You实现了Marry和Study接口
package com.xxxx.proxy;
public class You implements Marry, Study{
@Override
public void toMarry() {
System.out.println("我要结婚了...");
}
@Override
public void university() {
System.out.println("study in xidian...");
}
}
我们要对这两个接口中的方法进行代理,代理程序的书写如下:
package com.xxxx.proxy;
public class JdkHandlerTest {
public static void main(String[] args) {
//目标对象
You you = new You();
//得到代理类,用jdkHandler表示
JdkHandler jdkHandler = new JdkHandler(you);
//得到代理对象 用marry表示这里 左边是目标对象所实现的接口 右边是通过代理类获取的代理对象
Marry marry =(Marry) jdkHandler.getproxy();
//通过代理对象调用目标对象的方法
marry.toMarry();
System.out.println("--------");
Study study = (Study) jdkHandler.getproxy();
study.university();
}
}
CGlib动态代理
CGlib的思路是通过目标类生成代理类的父类,需要实现MethodInceptor接口
package com.xxxx.CGlib;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CglibInterceptor implements MethodInterceptor {
/**
* 拦截器
* 1 目标对象的方法调用
* 2 行为增强
* @param o cglib动态生成的代理类的实例
* @param method 实体类所调用的都被代理的方法的引用
* @param objects 参数列表
* @param methodProxy 生成的代理类对方法的代理引用
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
//调用目标类的方法
Object obj = methodProxy.invoke(target,objects);
return obj;
}
/**
* 目标对象
*/
private Object target;
/**
* 通过构造器传入目标对象
* @param target
*/
public CglibInterceptor(Object target){
this.target = target;
}
/**
* 获取代理类
*
*/
public Object getProxy(){
//通过Enhancer对象中的create方法生成一个类,用于生成代理对象
Enhancer enhancer = new Enhancer();
//设置父类,将目标类作为代理类的父类
enhancer.setSuperclass(target.getClass());
//实现一个callback的子接口,括号里面放置的是拦截器,这里的拦截器是CglibInterceptor 也就是回调对象为本身对象
enhancer.setCallback(this);
//生成代理类对象并返回给调用者
return enhancer.create();
}
}
加入需要代理User类中的test方法
package com.xxxx.CGlib;
public class User {
public void test(){
System.out.println("cglib动态代理");
}
}
测试代码如下
package com.xxxx.CGlib;
import com.xxxx.proxy.Marry;
import com.xxxx.proxy.You;
public class CglibProxyTest {
public static void main(String[] args) {
You you = new You();
CglibInterceptor cglibInterceptor = new CglibInterceptor(you);
Marry marry=(Marry) cglibInterceptor.getProxy();
marry.toMarry();
User user = new User();
CglibInterceptor cglibInterceptor1 = new CglibInterceptor(user);
User user1 = (User) cglibInterceptor1.getProxy();
user1.test();
}
}
AOP
Spring的两大特性中的AOP就是基于动态代理实现的,AOP的注意点在于定义切面。
比如定义前置通知:
@Before("execution( chapter04.concert.Performance.perform(..))")*
其中execution(* chapter04.concert.Performance.perform(..))被称为AspectJ切点表达式,每一部分的讲解如下:
@Before:该注解用来定义前置通知,通知方法会在目标方法调用之前执行
execution:在方法执行时触发
*:表明我们不关心方法返回值的类型,即可以是任意类型
chapter04.concert.Performance.perform:使用全限定类名和方法名指定要添加前置通知的方法
(..):方法的参数列表使用(..),表明我们不关心方法的入参是什么,即可以是任意类型