动态代理有两种实现方式!
1:JDK的动态代理,是由JDK的java.lang.reflect.*包提供支持的,必须需要实现接口的一种方式.
2:CGLIB动态代理,是由第三方jar包实现,弥补了不需要接口实现的一种方式.
JDK动态代理
步骤:
1:编写服务类和接口,这个是真正的服务提供者
2:编写代理类,提供绑定和代理方法
接口类
public interface HelloService {
void sayHello(String name);
}
实现类
public class HelloServiceImpl implements HelloService {
@Override
public void sayHello(String name) {
System.out.print("hello "+name);
}
}
编写一个代理类,提供真实对象的绑定和代理方法。代理类的要求是实现InvocationHandler接口的代理方法。
public class HelloServiceProxy implements InvocationHandler {
/**
* 真实的服务对象
*/
private Object target;
public Object bind(Object target){
this.target = target;
System.out.println("target 加载器 : "+ target.getClass().getClassLoader().toString());
System.out.println("target 父类加载器 : "+ target.getClass().getClassLoader().getParent().toString());
//取得代理类
return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this); //jdk代理需要提供接口
}
/**
*
* @param proxy
* @param method
* @param args
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.print("############我是jdk动态代理###############");
Object result = null;
//反射方法调用前
System.out.println("动态代理开始>>>>>>>>>>>>>");
result = method.invoke(target,args);
System.out.println("动态代理结束>>>>>>>>>>>>>");
return target;
}
public static void main(String [] args){
HelloServiceProxy helloServiceProxy = new HelloServiceProxy();
HelloService helloService = (HelloService)helloServiceProxy.bind(new HelloServiceImpl());
helloService.sayHello("zengtaoping");
}
}
运行结果为:
上面这段代码让JDK产生一个代理对象。这个代理对象有三个参数:第一个参数target.getClass().getClassLoader()是哪个类加载器,第二个参数target.getClass().getInterfaces()是接口(代理对象挂在哪个接口下),第三个参数this代表当前HelloServiceProxy类,换句话说是使用HelloServiceProxy的代理方法作为对象的代理执行者,一旦绑定后,在进入代理对象方法调用的时候就会到HelloServiceProxy的代理方法上,代理方法有三个参数:第一个proxy是代理对象,第二个是当前调用的那个方法,第三个是方法的参数。比如说:现在HelloServiceImpl对象(obj)用bind方法绑定后,返回其占位,我们再调用proxy.sayHello("张三"),那么它就会进入到HelloServiceProxy的invoke()方法。而invoke参数中第一个便是代理对象proxy,方法便是sayHello,参数便是张三。
CGLIB动态代理
JDK提供的动态代理存在一个缺陷,就是你必须提供接口才可以使用。而CGLIB可以不需要,接下来我们看实现.
前面的HelloService和HelloServiceImpl都不需要修改,我们只要实现CGLIB的代理类。它的实现MethodInterceptor的代理方法如下
public class HelloServiceCgLib implements MethodInterceptor {
private Object target;
/**
* 创建代理对象
* @param target
* @return
*/
public Object getInstance(Object target){
this.target = target;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.target.getClass());
//回掉方法
enhancer.setCallback(this);
//创建代理对象
return enhancer.create();
}
/**
* 回掉方法
* @param o
* @param method
* @param objects
* @param methodProxy
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("############我是cglib动态代理###############");
Object result = null;
//反射方法调用前
System.out.println("cglib动态代理开始>>>>>>>>>>>>>");
result = methodProxy.invokeSuper(o,objects);
//反射方法之后
System.out.println("cglib动态代理结束>>>>>>>>>>>>>");
return target;
}
public static void main(String [] args){
HelloServiceCgLib helloServiceCgLib = new HelloServiceCgLib();
HelloService helloService = (HelloService)helloServiceCgLib.getInstance(new HelloServiceImpl());
helloService.sayHello("zengtaoping");
}
}
运行结果如下
getInstance方法只是需要具体类的实现就好了