什么是代理模式?
代理模式的定义:代理模式给某一对象提供一个代理对象,并由代理对象控制对原有对象的引用。通俗的来说就是我们所说的中介。
举个例子来介绍: 现在包租婆要租房子,一方面通过自己给客户介绍,另外一方面是将房子给中介公司,让其帮忙代理出租房子,用图展示如下:
代理模式涉及到如何角色:
- 客户端
- 代理对象
- 目标对象
- 代理对象和目标对象的公共接口
代理模式的优点
隔离作用:在某些情况下,一个客户端不想或者不能直接引用一个委托对象,而代理对象可以在客户端和委托对象之间起到中介作用,其特征是代理类和委托类实现相同接口
有哪几种代理模式?
1、静态代理
委托类
public class Landlady implements House {
public void sellHouse() {
System.out.println("我是女房东我需要租房子");
}
}
代理类
public class LandladyProxy implements House {
private Landlady landlady;
public LandladyProxy(Landlady landlady) {
this.landlady = landlady;
}
public void sellHouse() {
System.out.println("我是中介公司我是来帮包租婆租房子的");
landlady.sellHouse();
System.out.println("中介公司已经把房子租出去了");
}
}
租客类
public class Renter {
public static void main(String[] args) {
rentHouse();
}
public static void rentHouse(){
Landlady landlady = new Landlady();
LandladyProxy proxy = new LandladyProxy(landlady);
proxy.sellHouse();
}
}
委托类和代理类共同实现的接口
public interface House {
public void sellHouse();
}
代理类总结****
**优点:**可以做到在符合开闭原则的情况下对目标类进行功能扩展
**缺点:**我们得为每一个服务都得创建代理类,工作量太大,不易管理。同时接口一旦发生改变,代理类也得跟着修改
2、 动态代理
在动态代理中,我们不需要在手动去创建代理类,我们只需要编写一个动态处理器就可以了。真正的代理对象是由JDK在运行时为我们动态来创建的。
实现动态代理类的步骤
-
实现动态处理器 invocationHandler
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class HouseInvocationHandler implements InvocationHandler { /** * * @param proxy 代理对象 * @param method 委托类的的方法名称 * @param args 委托类方法参数 * @return 执行方法返回结果 * @throws Throwable */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println(method); System.out.println("这个方法是动态代理方法处理器"); return null; } public static void main(String[] args) { Object o = Proxy.newProxyInstance(House.class.getClassLoader(), new Class[]{House.class}, new HouseInvocationHandler()); if (o instanceof House) { House house = (House) o; house.sellHouse(); } } }
- 创建代理类对象
/** java.lang.reflect.Proxy#newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) loader类加载器 interfaces 被代理的接口类对象 动态处理器 */ Object o = Proxy.newProxyInstance(House.class.getClassLoader(), new Class[{House.class}, new HouseInvocationHandler());
- 转换为接口类实例,并使用代理类
public static void main(String[] args) { Object o = Proxy.newProxyInstance(House.class.getClassLoader(), new Class[]{House.class}, new HouseInvocationHandler()); if (o instanceof House) { House house = (House) o; house.sellHouse(); } } /执行结果 public abstract void com.aliyun.bean.House.sellHouse() 这个方法是动态代理方法处理器
动态代理总结:
**优点:**降低了对业务接口的耦合度
**缺点:**只能对接口进行代理,无法对非接口和非抽象类进行代理
3、 CGLIB代理
CGLIB是什么?
CGLIB是为了弥补jdk动态代理只能针对接口,而无法针对没有接口的类,CGLIB采用了非常底层字节码技术,其原理就是通过字节码技术为一个类创建一个子类,并在子类中采用方法拦截技术拦截所有的父类方法调用(可以说成是子类重写了父类的方法)。因为CGLIB是针对于类继承而设计的代理技术,那么对于类为final的是无法使用CGLIB代理
CGLIB使用步骤:1、导入CGLIB依赖包
<!-- https://mvnrepository.com/artifact/cglib/cglib --> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.2.10</version> </dependency>
2、创建目标类
import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; public class UserService { public void showUsers(){ System.out.println("this is user........."); } public String getResult(){ System.out.println("this is super getResult"); return String.valueOf(Math.random()); } public static void main(String[] args) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(UserService.class); enhancer.setCallback(new MethodInterceptor() { public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println(method.getName()); System.out.println("this is interceptor....."); System.out.println(methodProxy.getSuperName()); // 执行父类的方法 Object o1 = methodProxy.invokeSuper(o, objects); return o1; } }); Object o = enhancer.create(); if (o instanceof UserService) { UserService userService = (UserService) o; userService.showUsers(); System.out.println("=============================================================================>"); System.out.println(userService.getResult()); } } }
3、创建代理类
/* new MethodInterceptor() { /** o 被代理类 method 代理类的方法 objects 代理类的参数 MethodProxy 父类的引用,包含执行的父类的方法对象 */ public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println(method.getName()); System.out.println("this is interceptor....."); System.out.println(methodProxy.getSuperName()); // 执行父类的方法 Object o1 = methodProxy.invokeSuper(o, objects); return o1; } } */ Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(UserService.class); enhancer.setCallback(new MethodInterceptor() { public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println(method.getName()); System.out.println("this is interceptor....."); System.out.println(methodProxy.getSuperName()); // 执行父类的方法 Object o1 = methodProxy.invokeSuper(o, objects); return o1; } }); Object o = enhancer.create();
4、实现MethodInterceptor
/* new MethodInterceptor() { /** o 被代理类 method 代理类的方法 objects 代理类的参数 MethodProxy 父类的引用,包含执行的父类的方法对象 */ public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println(method.getName()); System.out.println("this is interceptor....."); System.out.println(methodProxy.getSuperName()); // 执行父类的方法 Object o1 = methodProxy.invokeSuper(o, objects); return o1; } } */
CGLIB代理总结
优点:弥补了JDK动态代理只能对于接口代理的缺点
缺点:对于类为final的无法代理
代理模式实践
SpringAOP
mybatis
等等
如有表达不足的请大家指出,谢谢能看完这篇文章