-
代理模式:为另一个对象提供一个替身或占位符,以便于控制对这个对象的访问
-
静态代理:
就是将一些在方法中重复的功能提取出来,通过一个专门的类去封装,在具体类中需要的时候就用那个专门的类的对象去调用
-
动态代理:
原理和静态代理差不多,只是用了一个反射的接口,去调用一些方法方便进行动态调度
-
动态代理的步骤就是:
先把代理类实例化,再实例化被代理类,将被代理类的对象传到代理类的方法中,因为是Object类型,所以需要转型再输出那个方法
静态代理
package com.carl.agent;
/**
* @Version 1.0.0
* @author carl蔡先生
* @Date 2022/10/03
* @Description 租房
*/
public interface RentHouse {
/**
* 租房流程
*/
void rent();
}
package com.carl.agent;
/**
* @Version 1.0.0
*
* @author carl蔡先生
* @Date 2022/10/03
* @Description 房东--要租房
*/
public class Landlord implements RentHouse {
@Override
public void rent() {
System.out.println("三室一厅,独厨独卫,家具齐全!价格面议");
}
}
package com.carl.agent;
/**
* @Version 1.0.0
*
* @author carl蔡先生
* @Date 2022/10/03
* @Description 静态代理
*/
public class StaticProxy {
private RentHouse rentHouse;
public StaticProxy(){
}
public StaticProxy(RentHouse rentHouse){
this.rentHouse = rentHouse;
}
public void rent(){
rentHouse.rent();
System.out.println("中介费用为房价的一半!");
}
}
@Test
public void testStaticAgent(){
//租房直接找房东
RentHouse rentHouse=new Landlord();
//办理租房流程
rentHouse.rent();
//找中介租房子
StaticProxy staticProxy=new StaticProxy(rentHouse);
//中介给你办理租房流程
staticProxy.rent();
}
代理的好处
-
可以使真实角色的操作更加纯粹,不用关注一些公共的业务
-
公共的业务交给代理角色,实现业务的分工
-
公共业务发生扩展的时候,方便集中管理
缺点:
- 一个真实角色就会产生一个代理角色,代码量增加,开发效率变低
例如:
UserService作为抽象角色,UserServiceImpl作为一个真实角色,需要每次访问该业务类中的方式的时候,都要做权限判断,判断权限是否满足要求
这个时候使用代理角色,调用方法时,都统一进行权限管理,这样权限判断的业务和查询User表的业务就分离了,互不影响。当UserServiceImpl增加一些业务,也可以通过代理,增加权限管理的业务,统一集中管理
这就是AOP的逻辑
动态代理
动态代理和静态代理的角色一致
动态代理的两大类
-
基于接口的动态代理(JDK动态代理)
-
基于类的动态代理(CGlib动态代理)
-
java字节码实现:javasist
Proxy类和InvocationHandle类
Proxy类
Proxy提供了创建动态代理类和实例的静态方法(newProxyInstance())
常用方法
-
getInvocationHandler(Object proxy):返回指定代理实例的调用处理程序
-
getProxyClass(ClassLoader loader,类<?>…interfaces):给出类加载器和接口的代理类
-
isProxyClass():如果当且仅当使用getProxyClass方法或newProxyInstance方法将指定的类动态生成代理类时,返回true
-
newProxyInstance(ClassLoader loader,类<?>[] interfaces,InvocationHandler h):返回指定接口的代理类的实例,该接口将方法调用分派给指定的调用处理程序
JDK提供了两种方式获取动态代理类的实例:
InvocationHandler handler = new MyInvocationHandler(...);
Class<?> proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(), Foo.class);
Foo f = (Foo) proxyClass.getConstructor(InvocationHandler.class).newInstance(handler);
/**
* 获取代理
* @return {@link Object }
*/
public Object getProxy() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
/*
* 第一个参数:this.getClass().getClassLoader(),使用handler对象的classLoader加载代理对象
* 第二个参数:handler.getClass().getInterfaces(),为代理类提供真实对象的接口,便于调用接口中的所有方法
* 第三个参数:this,InvocationHandler对象
*/
return Proxy.newProxyInstance(this.getClass().getClassLoader(), handler.getClass().getInterfaces(),this);
}
InvocationHandler类
InvocationHandler类是被代理实例调用处理程序的接口
Object invoke(Object proxy, Method method, Object[] args):通过反射获取被代理类的示例
proxy:代理类代理的真实对象
method:通过反射获取到的需要调用某个对象的方法
args:指代代理对象方法的传递参数
在invoke对象中,调用被代理对象的处理程序,并可以进行增强,具体实现如下:
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = method.invoke(handler, args);
return result;
}
动态代理具体实现步骤:
package com.carl.proxy.dynamic;
/**
* @Version 1.0.0
*
* @author carl蔡先生
* @Date 2022/10/03
* @Description 租房
*/
public interface RentHouse {
/**
* 租金
*/
void rent();
}
package com.carl.proxy.dynamic;
/**
* @Version 1.0.0
*
* @author carl蔡先生
* @Date 2022/10/03
* @Description 房东--要租房
*/
public class Landlord implements RentHouse {
@Override
public void rent() {
System.out.println("三室一厅,独厨独卫,家具齐全!价格面议");
}
}
package com.carl.proxy.dynamic;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @Version 1.0.0
* @see InvocationHandler
* @author carl蔡先生
* @Date 2022/10/03
* @Description 动态代理--必须实现InvocationHandler接口
*/
public class DynamicProxy implements InvocationHandler {
/**
* 被代理对象
*/
private RentHouse rentHouse;
public void setRentHouse(RentHouse rentHouse) {
this.rentHouse = rentHouse;
}
/**
* 被代理对象的处理程序
* @param proxy 代理对象
* @param method 方法
* @param args 参数
* @throws Throwable 抛出最高异常
* @return {@link Object }
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//前后增加操作
lookHouse();
Object result = method.invoke(rentHouse, args);
fare();
return result;
}
/**
* 获取代理类
* @return {@link Object }
*/
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(), rentHouse.getClass().getInterfaces(),this);
}
public void lookHouse(){
System.out.println("中介带看房源!");
}
public void fare(){
System.out.println("中介收中介费!");
}
}
package com.carl.proxy.util;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @Version 1.0.0
* @see InvocationHandler
* @author carl蔡先生
* @Date 2022/10/04
* @Description 通用代理调用处理程序
*/
public class ProxyInvocationHandler implements InvocationHandler {
/**
* @see Object
* 被代理对象
*/
private Object handler;
public ProxyInvocationHandler() {
}
public ProxyInvocationHandler(Object handler) {
this.handler = handler;
}
/**
* 获取代理
* @return {@link Object }
*/
public Object getProxy() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
/*
* 第一个参数:this.getClass().getClassLoader(),使用handler对象的classLoader加载代理对象
* 第二个参数:handler.getClass().getInterfaces(),为代理类提供真实对象的接口,便于调用接口中的所有方法
* 第三个参数:this,InvocationHandler对象
*/
return Proxy.newProxyInstance(this.getClass().getClassLoader(), handler.getClass().getInterfaces(),this);
}
/**
* @param proxy 代理类
* @param method 方法
* @param args 参数
* @throws Throwable 抛出异常
* @return {@link Object }
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = method.invoke(handler, args);
return result;
}
}