谈到代理模式,绕不开静态代理、动态代理
谈到动态代理绕不开jdk方式和cglib方式
自然而言也就想到了spring aop的实现就是用了动态代理
AOP编程中如何选择代理模式:
- 目标对象需要实现接口,用JDK代理
- 目标对象不需要实现接口,用Cglib代理
还有mybatis mapper 生成接口的代理同样用了动态代理
jdk方式
核心类:
java.lang.reflect.InvocationHandler
核心方法:
java.lang.reflect.Proxy#newProxyInstance
上代码
/**
* @author wmx
* @date 2019-09-04
*/
public class ProxyDemo {
public static void main (String[] args) {
HelloImpl hello = new HelloImpl();
MyInvocationHandler handler = new MyInvocationHandler(hello);
// 构造代码实例
Hello proxyHello = (Hello) Proxy.newProxyInstance(HelloImpl.class.getClassLoader(), HelloImpl.class.getInterfaces(), handler);
// 调用代理方法t
proxyHello.sayHello();
}
}
interface Hello {
void sayHello();
}
class HelloImpl implements Hello {
@Override
public void sayHello() {
System.out.println("Hello World");
}
}
class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//写自己包裹代理方法的一些操作
System.out.println("before invoking sayHello");
Object result = method.invoke(target, args);
System.out.println("after invoking sayHello");
return result;
}
}
输出:
before invoking sayHello
Hello World
after invoking sayHello
小结:
代理者要实现InvocationHandler
接口,实现invoke方法
invoke方法就是调用被代理者的方法,然后可以做一些增强,
代理者要持有被代理者的一个引用,
这里涉及到反射的一些知识,反射的知识也是必须要熟悉的
这种实现仍然有局限性,因为它是以接口为中心的,相当于添加了一种对于被调用者没有太大意义的限制。
代码简单
cglib方式
需要引入一个依赖:
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
核心类:
Enhancer
/**
* @author wmx
* @date 2019-09-04
*/
public class CglibDemo {
public static void main(String[] args) {
SayHello proxy = (SayHello) getProxy(new SayHello());
proxy.sayHello("xinye");
}
public static Object getProxy(SayHello target){
// 创建增强器 底层是二进制码实现
Enhancer enhancer = new Enhancer();
enhancer.setInterfaces(target.getClass().getInterfaces());
//注意:cglib创建的代理对象都是目标对象的子类
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("before invoke");
Object result = method.invoke(target,args);
System.out.println("after invoke");
return result;
}
});
return enhancer.create();
}
}
class SayHello {
public void sayHello(String msg) {
System.out.println("Hello World "+msg);
}
}
输出:
before invoke
Hello World xinye
after invoke
小结:
比较JDK proxy,cglib克服对接口的依赖
cglib动态代理采取的是创建目标类的子类的方式,因为是子类化,我们可以达到近似使用被调用者本身的效果。
性能稍高
Cglib包的底层是通过使用字节码处理框架ASM来转换字节码并生成新的类,这一个也是面试经常爱问的
说点什么
您将是第一位评论人!