为某一个对象(委托类)提提供一个代理(代理类),用来控制这个对象的访问。委托类和代理类有一个共同的父类或父接口。代理类会对请求做预处理、过滤,将请求分配给指定对象
代理模式在java开发中是一种比较常见的设计模式。设计目的旨在为服务类和客户类之间插入其他功能,插入的功能对于调用者是透明的,起到伪装控制的作用。
如住房的例子:房客、中介、房东;对应于代理模式中即:客户类、代理类、委托类(类代理类)
代理类 和 委托类 具有相似的行为(共有)
代理类 增强 委托类的行为
![\[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-c6CM9LFe-1650266348261)(image/代理模式.png)\]](https://img-blog.csdnimg.cn/ec26b6e0ddaa433a97e266a887695721.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5aS05Y-R5Zyo6aOO5Lit5ZOt5rOj,size_15,color_FFFFFF,t_70,g_se,x_16)
静态代理
某个对象提供一个代理,代理角色固定,以控制对这个对象的访问。代理类和委托类有共同的父类或父接口,这样在任何使用委托类对象的地方都可以用代理对象替代。
代理类负责请求的预处理、过滤,将请求分派给委托类处理、以及委托类执行完请求后的后续处理。
public interface RentHouse {
public void toRentHouse();
}
public class You implements RentHouse{
@Override
public void toRentHouse() {
System.out.println("目标对象,租到房子");
}
}
public class AgencyProxy implements RentHouse{
private RentHouse rentHouse;
public AgencyProxy(RentHouse rentHouse) {
this.rentHouse = rentHouse;
}
@Override
public void toRentHouse() {
System.out.println("中介找房");
rentHouse.toRentHouse();
System.out.println("中介收钱");
}
}
public class com.zh.starter.StarterProxy {
public static void main(String[] args) {
AgencyProxy proxy = new AgencyProxy(new You());
proxy.toRentHouse();
}
}
动态代理
相比于静态代理,动态代理在创建代理对象上更加灵活,动态代理类的字节码在程序运行时,由Java反射机制动态产生。
它会根据需要,通过反射机制在程序运行期,动态的为目标对象创建代理对象,无需程序员手动编写源码。动态代理不仅简化了编程工作,
而且提高了软件系统的可扩展性,因为反射机制可以生成任意类型的动态代理类。代理的行为可以代理多个方法,即满足产生需要的同时又达到代码通用的的目的。
1. 目标对象不固定
2. 在应用程序执行时动态创建目标对象
3. 代理对象会增强目标对象的行为
JDK动态代理
需要使用JDK动态代理的类,必须要有接口实现
Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类,此类提供了如下操作方法
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
返回一个指定接口的代理类的实例方法调用分派到指定的调用处理程序,(返回代理对象)
loader:一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象加载
interfaces:一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,
那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法
h:一个InvocationHandler接口,表示代理实例的调用处理程序实现的接口。每个代理实例都具有一个关联的调用处理程序。对代理实例调用方法时,
将对方法调用进行编码并将其指派到它的调用处理程序的 invoke 方法(传入InvocationHandler接口)
- 定义RentHouse接口和两个抽象方法
public interface RentHouse {
public void toRentHouse();
public String toRentHouse2(String name);
}
- 定义目标类,实现接口,重写方法
public class You implements RentHouse{
@Override
public void toRentHouse() {
System.out.println("目标对象,租到房子");
}
@Override
public String toRentHouse2(String name) {
System.out.println(name+"目标对象,租到房子");
return "result01";
}
}
- 定义JDK动态 代理类
public class JdkDynamicProxy {
private Object target;
public JdkDynamicProxy(Object target) {
this.target = target;
}
public Object getProxy(){
Object object = null;
ClassLoader classLoader = this.getClass().getClassLoader();
Class[] interfaces = target.getClass().getInterfaces();
InvocationHandler invocationHandler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(method.getName());
System.out.println(args.length);
System.out.println(args[0]);
System.out.println("invoke...调用");
Object result = method.invoke(target, args);
System.out.println("result:"+result);
return result;
}
};
object = Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
return object;
}
}
- 测试类
public class com.zh.starter.StarterJdkDynamicProxy {
public static void main(String[] args) {
RentHouse target2 = new You();
JdkDynamicProxy jdkDynamicProxy2 = new JdkDynamicProxy(target2);
RentHouse object2 = (RentHouse) jdkDynamicProxy2.getProxy();
object2.toRentHouse2("张三");
}
- 结果
CGLIB 动态代理
继承思想,代理类是目标类的子类,代理类对目标类中的方法进行重写
JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能使用JDK的动态代理,CGLIB是针对类来实现代理的,
它的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。
- 定义没有接口实现的目标类
public class User {
public void toMarry(){
System.out.println("结婚了");
}
}
- 定义CglibDynamicProxy 动态代理类
public class CglibProxy {
private Object target;
public CglibProxy(Object target) {
this.target = target;
}
public Object getProxy(){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
MethodInterceptor interceptor = new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("CGLIB...指定方法执行前");
Object result = method.invoke(target, objects);
System.out.println("CGLIB...指定方法执行后");
return result;
}
};
enhancer.setCallback(interceptor);
return enhancer.create();
}
}
- 测试
public class CglibTest {
public static void main(String[] args) {
User user = new User();
CglibProxy cglibProxy1 = new CglibProxy(user);
User user1 = (User) cglibProxy1.getProxy();
user1.toMarry();
}
}
- 测试结果