代理通常有两种代理方式,一种是动态代理,一种是静态代理,动态代理一般有两种实现方式,一种是通过JDK自身实现代理,还有一种就是通过开源库cglib实现代理。
1.静态代理
静态代理需要三个类,一个接口类,一个接口实现类,还有一个是接口的代理类,下面与一个例子
接口类如下,就写一个需要代理的接口方法。
public interface A {
void something();
}
接口的实现类
public class ImplementA implements A {
@Override
public void something() {
System.out.println("do something");
}
}
接口的代理类public class ProxyA implements A {
private A a;
public ProxyA(A a){
this.a = a;
}
@Override
public void something() {
before();
a.something();
after();
}
private void before(){
System.out.println("before do something");
}
private void after(){
System.out.println("after do something");
}
}
接口的代理类添加了一些在代理之前和之后的方法,来模仿代理的一个作用(验证等) 最后是一个测试类
public class Test {
public static void main(String[] args){
A a = new ImplementA();
ProxyA proxyA = new ProxyA(a);
proxyA.something();
}
}
测试结果 静态代理的优缺点:
优点:业务类只需要关注业务逻辑本身,保证了业务类的重用性。这是代理的共有优点。
缺点:
1)代理对象的一个接口只服务于一种类型的对象,如果要代理的方法很多,势必要为每一种方法都进行代理,静态代理在程序规模稍大时就无法胜任了。
2)如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。
缺点:
1)代理对象的一个接口只服务于一种类型的对象,如果要代理的方法很多,势必要为每一种方法都进行代理,静态代理在程序规模稍大时就无法胜任了。
2)如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。
2.动态代理(JDK)
静态代理的优缺点非常明显,为了解决静态代理的缺点,所有我们使用动态代理,动态代理有两种,第一种就是JDK代理,第二种是cglib代理,我们先来看JDK代理,下面来举一个例子。
和静态代理一样需要一个接口类
public interface A {
void something();
}
一个接口的实现类public class ImplementA implements A {
@Override
public void something() {
System.out.println("do something");
}
}
代理类package proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* Created by Jackie on 2017/7/23.
* JDK 动态代理
*/
public class JDKProxy implements InvocationHandler {
private Object target;
public JDKProxy(Object target){
this.target = target;
}
public Object bind(){
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces() , this);
}
/**
*
* @param proxy 需要代理的实现类
* @param method 调用的方法
* @param args 调用的方法需要的参数
* @return result
* @throws Throwable 异常
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
if (method.getName().equals("something")){
before();
result = method.invoke(target , args);
after();
return result;
}
return null;
}
private void before(){
System.out.println("before do something");
}
private void after(){
System.out.println("after do something");
}
}
通过bind获取接口实现的代理类,注意是接口的实现代理类,这也是JDK代理的一个缺点,只能代理接口的实现类,这时候就需要cglib的代理。3.cglib代理
JDK动态代理只能代理接口的实现类,但是cglib能代理不是接口的实现类,下面举一个例子
我们还是需要一个接口
public interface A {
void something();
}
一个被代理对象/**
* Created by Jackie on 2017/7/23.
* 并没有实现接口
*/
public class CglibAImpl {
public void something(){
System.out.println("do something");
}
}
使用cglib代理package proxy;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* Created by Jackie on 2017/7/23.
*
*/
public class CglibProxy implements MethodInterceptor {
private Object target;
public CglibProxy(Object target){
this.target = target;
}
public Object bind(){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
Object result = null;
if (method.getName().equals("something")){
before();
result = methodProxy.invokeSuper(o , objects);
after();
}
return result;
}
private void before(){
System.out.println("before do something");
}
private void after(){
System.out.println("after do something");
}
}
测试类package proxy;
/**
* Created by Jackie on 2017/7/23.
*
*/
public class CglibProxyTest {
public static void main(String[] args){
CglibProxy cglibProxy = new CglibProxy(new CglibAImpl());
CglibAImpl cglibA = (CglibAImpl) cglibProxy.bind();
cglibA.something();
}
}
测试结果 JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。