动态代理
JDK动态代理
JDK动态代理主要用到Proxy
类和InvocationHandler
接口,通过使用他们就可以生成JDK动态代理类和动态代理对象。
Proxy提供如下两个方法创建动态代理类和动态代理实例。
-
public static Class<?> getProxyClass(ClassLoader loader,Class<?>...interfaces)
:创建一个动态代理类对应的Clas对象,该代理类将实现了interfaces接口。第一个Classloader参数指生成被代理类或接口的类加载器。 -
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
:直接创建一个动态代理对象,该代理对象的实现类实现了interfaces所指定的接口,执行代理对象的每个方法都会被替换执行InvocationHandler对象的invoke方法。
下面作了一个演示,其中对象foo是由Proxy
的getProxyClass
方法先创建一个动态代理类的Clas对象,再创建动态代理实例,对象foo1是由Proxy
的newProxyInstance
直接创建一个动态代理实例。
/**
* Created by SqMax on 2018/4/25.
*/
interface Foo {
void info();
}
public class ProxyClassTest {
public static void main(String[] args) throws Exception {
Class proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(),
new Class[]{Foo.class});
Constructor constructor = proxyClass.getConstructor(new Class[]{InvocationHandler.class});
Foo foo = (Foo) constructor.newInstance(new Object[]{
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("executing method:" + method);
return null;
}
}
});
Foo foo1 = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(), new Class[]{Foo.class},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("executing method:" + method);
return null;
}
});
foo.info();
foo1.info();
}
}
上面程序执行结果如下:
executing method:public abstract void top.sqmax.chapter18.Foo.info()
executing method:public abstract void top.sqmax.chapter18.Foo.info()
动态代理与AOP
有如下接口和类:
public interface Dog {
void info();
void run();
}
public class GunDog implements Dog {
@Override
public void info() {
System.out.println("i am a gundog.");
}
@Override
public void run() {
System.out.println("i am running.");
}
}
想要在GunDog的info和run方法执行前和执行后执行一些通用的动作method1,method2()。
public class DogUtil {
public void method1(){
System.out.println("---mock first common method---");
}
public void method2(){
System.out.println("---mock second common method2----");
}
}
可以使用动态代理。
public class MyProxyFactory {
public static Object getProxy(Object target){
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),new InvocationHandler(){
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
DogUtil du=new DogUtil();
du.method1();
Object result=method.invoke(target,args);
du.method2();
return result;
}
});
}
}
下面测试,生成对GunDog的动态代理实例。
public class Test {
public static void main(String[] args) {
Dog target = new GunDog();
Dog dog = (Dog) MyProxyFactory.getProxy(target);
dog.info();
dog.run();
}
}
执行结果
---mock first common method---
i am a gundog.
---mock second common method2----
---mock first common method---
i am running.
---mock second common method2----
Cglib动态代理
Cglib动态代理是第三方技术,他的优势在于不需要提供接口,只要一个非抽象类能实现动态代理。Cglib动态代理的两个关键类是Enhancer,MethodInterceptor。
使用Cblib动态代理首先要引入第三方的jar包:
<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
下面是一个具体的使用例子:
public class CglibProxy implements MethodInterceptor {
public Object getProxy(Class cls) {
Enhancer enhancer=new Enhancer();
enhancer.setSuperclass(cls);
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("在调度真实对象前的服务");
Object result = methodProxy.invokeSuper(o, objects);
System.out.println("在调度真实对象之后的服务");
return result;
}
public static void main(String[] args) {
CglibProxy cglibProxy=new CglibProxy();
HelloWorld proxy = (HelloWorld) cglibProxy.getProxy(HelloWorldImpl.class);
proxy.sayHelloWorld();
}
}
上面的Enhancer的setSuprclas()方法表明是为了那个类(被代理类)设置增强,setCallback()设置那个类去为它代理。
输出结果如下:
在调度真实对象前的服务
hello world
在调度真实对象之后的服务