前言
本文主要说代理的三种实现方式,不涉及概念性内容
1. 静态代理
案例
已知车站具有售票功能,同时网上售票软件也可以进行售票。既网上售票软件代理车站售票功能。
共同的接口
车票接口,定义售票方法,不提供实现,仅供外部调用
public interface Ticket {
/**
* 售票
* @return void
* 时间:2018年4月25日
*/
public void sellTicket();
}
实现类
车站类,实现车票接口中的售票方法
public class Station implements Ticket{
@Override
public void sellTicket() {
System.out.println("正在出售车票");
}
}
代理类
网上售票代理类,注入被代理对象车站类,并实现车票接口的售票方法
public class NetworkProxy implements Ticket{
private Station station = new Station();
@Override
public void sellTicket() {
station.sellTicket();
this.success();
}
public void success() {
System.out.println("出票");
}
}
客户类
测试网上售票代理执行
public class ProxyTest {
public static void main(String[] args) {
NetworkProxy networkProxy = new NetworkProxy();
networkProxy.sellTicket();
}
}
从上面的例子我们可以看出,在代理类中,我们注入了被代理对象,同时实现了功能接口,从而实现了代理。并且在被代理对象执行方法前后可以添加一些需要的功能。
而这就是静态代理,静态代理的弊端就是,倘若我们想实现其他类的代理类,则需要为其另建代理类,这会显得十分麻烦。由此引出了动态代理。
2. 动态代理
在静态代理中,我们需要在代理类中手动注入需要的被代理对象,而动态代理是在程序运行中动态生成我们需要的被代理对象。
案例
已知车站具有售票功能,同时网上售票软件也可以进行售票。既网上售票软件代理车站售票功能。
功能接口
public interface Ticket2 {
/**
* 售票
* @return void
* 时间:2018年4月25日
*/
public void sellTicket();
}
被代理对象
public class Station2 implements Ticket2{
@Override
public void sellTicket() {
System.out.println("正在出售车票");
}
}
代理对象
实现java.lang.reflect包下的InvocationHandler接口,通过构造方法将被代理对象注入,并重写invoke()方法
public class DynamicProxy implements InvocationHandler{
/**
* 被代理的对象
*/
private Object target;
public DynamicProxy(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object object = method.invoke(target, args);
this.success();
return object;
}
private void success() {
System.out.println("出票中");
}
}
测试类
public class DynamicProxyTest {
public static void main(String[] args) {
Ticket2 ticket = new Station2();
DynamicProxy dynamicProxy = new DynamicProxy(ticket);
//创建代理对象
Ticket2 proxy = (Ticket2)Proxy.newProxyInstance(
//功能接口实现类的类加载器
ticket.getClass().getClassLoader(),
//功能接口实现类的所有接口
ticket.getClass().getInterfaces(),
//动态代理对象
dynamicProxy
);
proxy.sellTicket();
}
}
当然,我们可以对上面的动态代理进行一定的优化。
代理对象
public class DynamicProxy implements InvocationHandler{
/**
* 被代理的对象
*/
private Object target;
public DynamicProxy(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object object = method.invoke(target, args);
this.success();
return object;
}
private void success() {
System.out.println("出票中");
}
/**
* 获取代理对象
* @return T
* 时间:2018年4月25日
*/
@SuppressWarnings("unchecked")
public <T> T getProxy() {
return (T) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
this
);
}
}
测试类
public class DynamicProxyTest {
public static void main(String[] args) {
Ticket2 ticket2 = new Station2();
DynamicProxy dynamicProxy = new DynamicProxy(ticket2);
Ticket2 proxy = dynamicProxy.getProxy();
proxy.sellTicket();
}
}
至此,java动态代理就结束了。但是,代理就这样结束了吗?并没有。
!!重点!!!
java动态代理,只能为接口创建代理,返回的代理对象也只能转换到某个接口类型。如果一个类没有接口,或者希望代理非接口中定义的方法,那就没办法了。
由此,又引出了cglib代理。
3. cglib代理
cglib动态的创建了一个类,但是这个类的父类是被代理的类,代理类重写了父类所有的public和非final方法,改为调用callback中的相关方法。 https://github.com/cglib/cglib
案例
已知车站具有售票功能,同时网上售票软件也可以进行售票。既网上售票软件代理车站售票功能。
功能接口
public interface Ticket3 {
/**
* 售票
* @return void
* 时间:2018年4月25日
*/
public void sellTicket();
}
被代理对象
public class Station3 implements Ticket3{
@Override
public void sellTicket() {
System.out.println("正在出售车票");
}
}
代理对象
代理对象需实现MethodInterceptor接口,并重写intercept()方法
public class CGLibProxy implements MethodInterceptor {
/**
* 方法级别的代理
*/
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
// 方法执行前
before();
Object object = proxy.invokeSuper(obj, args);
// 方法执行后
after();
return object;
}
@SuppressWarnings("unchecked")
public <T> T getProxy(Class<T> cls) {
return (T) Enhancer.create(cls, this);
}
private void after() {
System.out.println("方法执行前");
}
private void before() {
System.out.println("方法执行后");
}
}
测试类
public class CGLibTest {
public static void main(String[] args) {
CGLibProxy cgLibProxy = new CGLibProxy();
Ticket3 proxy = cgLibProxy.getProxy(Station3.class);
proxy.sellTicket();
}
}
动态代理与cglib代理区别
Java SDK代理:
面向的是一组接口, 它为这些接口动态创建了一个实现类,接口的具体实现逻辑是通过自定义的InvocationHandler实现的,这个实现是自定义的,也就是说,其背后都不一定有真正被代理的对象,也可能多个实际对象,根据情况动态选择。
jdk动态代理生成的代理类:
继承了Proxy类,实现了代理的接口,由于java只支持单继承,因此被代理类继承了Proxy类之后就无法再继承其他类,所以JDK的动态代理不支持对实现类的代理,只支持接口的代理。生成的代理类格式如下:public HelloImpl extends Proxy implements Hello
cglib代理:
面向的是一个具体的类,它动态创建了一个新类,继承了该类,重写了其方法。
cglib是针对类来进行代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法增强,因为采用的是继承,所以不能对final修饰的类进行代理。cglib采用非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。
以上内容参考
https://blog.csdn.net/noaman_wgs/article/details/72810255
https://blog.csdn.net/qq924862077/article/details/74625967