代理的相关术语
代理:降费核心的逻辑剥离出来以后封装在这些非核心逻辑的类、对象、方法
目标:背代套用了非和核心的逻辑代码的类 对象 方法。
代理就是将被代理类包在代理类当中 是被代理类成为代理类的成员方法 同时借助多态实现
静态代理与动态代理
代理解决的是如果我们项目要完成一个项目,需要使用的类不足以完成任务 但该类我们不能随意进行修改 这时候我们就需要进行代理的使用 在不改变源代码的同时实现代码功能的添加,在后续的spring框架中 aop就使用动态代理实现了切面的添加
servlect 方法得实现也采用了代理的方法(可能)
代理设计模式的原理: 使用一个代理将对象包装起来, 然后用该代理对象取代原始对象。任何对原 始对象的调用都要通过代理。代理对象决定是否以及何时将方法调用转到原始对象上。
代理类相当于中介将我们常遭的被代理类封装起来,然后通过调用代理类来调用被代理类
动态代理是指客户通过代理类来调用其它对象的方法,并且是在程序运行时 根据需要动态创建目标类的代理对象。
动态代理相比于静态代理的优点: 抽象角色中(接口)声明的所有方法都被转移到调用处理器一个集中的方法中 处理,这样,我们可以更加灵活和统一的处理众多的方法。
静态代理
package 动态代理;
/**
* Created with IntelliJ IDEA.
*
* @author : hcj
* @version : 1.0
* @Project : java8新特性
* @Package : 动态代理
* @ClassName : StaticPROXY.java
* @createTime : 2023/2/6 18:47
* @Description : 静态代理举例
*/
interface ClothFactory {
void produceCloth();
}
//代理类
class ProxyClothFactory implements ClothFactory {
private ClothFactory factory; // 拿被代理类对象进行实例化
public ProxyClothFactory(ClothFactory factory) {
this.factory = factory; // 多态 相当于 ClothFactory factory = new ProxyClothFactory();
}
@Override
public void produceCloth() {
System.out.println("代理工厂要做准备工作了");
factory.produceCloth();
System.out.println("代理工厂要做收尾工作了");
}
}
// 被代理类
//被代理类
class NikeClothFactory implements ClothFactory {
@Override
public void produceCloth() {
System.out.println("Nike工厂生产一批运动服");
}
}
public class StaticProxy {
public static void main(String[] args) {
//创建被代理类的对象
ClothFactory nike = new NikeClothFactory();
//创建代理类的对象
ClothFactory proxyClothFactory = new ProxyClothFactory(nike);
proxyClothFactory.produceCloth();
}
}
动态代理
动态代理中 代理类是动态生成的
根据你的 被代理类动态生成对应的接口来代理对你的执行
package 动态代理;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* Created with IntelliJ IDEA.
*
* @author : hcj
* @version : 1.0
* @Project : java8新特性
* @Package : 动态代理
* @ClassName : ProxyTest.java
* @createTime : 2023/2/6 19:02
* @Description : 动态代理实例
*/
interface Human{
String getBelief();
void eat(String food);
}
//被代理类
class SuperMan implements Human{
@Override
public String getBelief() {
return "I believe I can fly!";
}
@Override
public void eat(String food) {
System.out.println("我喜欢吃" + food);
}
}
class HumanUtil{
public void method1(){
System.out.println("====================通用方法一====================");
}
public void method2(){
System.out.println("====================通用方法二====================");
}
}
/*
要想实现动态代理,需要解决的问题?
问题一:如何根据加载到内存中的被代理类,动态的创建一个代理类及其对象。
问题二:当通过代理类的对象调用方法a时,如何动态的去调用被代理类中的同名方法 。
*/
class ProxyFactory{
//调用此方法,返回一个代理类的对象。解决问题一
public static Object getProxyInstance(Object obj){//obj:被代理类的对象
MyInvocationHandler handler = new MyInvocationHandler();
// 获取被代理类对象
handler.bind(obj);
// Proxy.newProxyInstance(类加载器,被代理类的接口,InvocationHandler);
//invocationHandler:设置代理对象实现被代理对象方法的过程,即代理类中如何重写接口中的抽象方法(动态的执行被代理类对象的方法)
return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),handler);
}
}
class MyInvocationHandler implements InvocationHandler {
private Object obj;//需要使用被代理类的对象进行赋值
public void bind(Object obj){
this.obj = obj;
}
//当我们通过代理类的对象,调用方法a时,就会自动的调用如下的方法:invoke()
//将被代理类要执行的方法a的功能就声明在invoke()中
/**
* proxy:代理对象
* method:代理对象需要实现的方法,即其中需要重写的方法
* args:method所对应方法的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
HumanUtil util = new HumanUtil();
util.method1();
//method:即为代理类对象调用的方法,此方法也就作为了被代理类对象要调用的方法
//obj:被代理类的对象
Object returnValue = method.invoke(obj,args);
util.method2();
//上述方法的返回值就作为当前类中的invoke()的返回值。
return returnValue;
}
}
public class ProxyTest {
public static void main(String[] args) {
SuperMan superMan = new SuperMan();
//proxyInstance:代理类的对象
// 这里只能是Human 动态代理过程中是寻找superman实现了什么接口 在这里 的接口human 该方法无法确定Hunman接口下层的superman
Human proxyInstance = (Human) ProxyFactory.getProxyInstance(superMan);
//当通过代理类对象调用方法时,会自动的调用被代理类中同名的方法
String belief = proxyInstance.getBelief();
System.out.println(belief);
proxyInstance.eat("四川麻辣烫");
System.out.println("*****************************");
NikeClothFactory nikeClothFactory = new NikeClothFactory();
ClothFactory proxyClothFactory = (ClothFactory) ProxyFactory.getProxyInstance(nikeClothFactory);
proxyClothFactory.produceCloth();
}
}
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
//检查InvocationHandler是否为空,为空抛出空指针异常
Objects.requireNonNull(h);
//克隆拿到接口
final Class<?>[] intfs = interfaces.clone();
//进行安全校验
final SecurityManager sm = System.getSecurityManager();
//检查是否能被代理
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
/*
* Look up or generate the designated proxy class.
* 得到代理类
*/
Class<?> cl = getProxyClass0(loader, intfs);
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
//通过构造方法得到代理类的对象
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
}
//new得到代理对象
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException|InstantiationException e) {
throw new InternalError(e.toString(), e);
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString(), t);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString(), e);
}
}
从上面可以看出 Class<?> cl = getProxyClass0(loader, intfs); 这行代码最重要,它可以得到一个代理对象,下面是 Proxy#getProxyClass0 的源码:
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
// If the proxy class defined by the given loader implementing
// the given interfaces exists, this will simply return the cached copy;
// otherwise, it will create the proxy class via the ProxyClassFactory
//如果接口的代理类已经存在缓存中了,直接从缓存中取出来返回,如果不存在则通过ProxyClassFactory创建一个并放入缓存中供下次使用
return proxyClassCache.get(loader, interfaces);
}
参考:
(55条消息) 类加载器详细解释_是云佐丫的博客-CSDN博客_类加载器