JDK动态代理的实现原理

JDK动态代理的实现原理

转载:By:芦青

1.引言

在开发中过程中,我们经常性的会对一个对象的方法进行增强,当然如果要增强一个对象的方法,我们会有很多种方式,

那么动态代理肯定是其中的一种方式,但是很多情况下,我们只会去使用动态代理,对动态代理的实现原理并不是很清晰,那这里我们就可以来聊一聊JDK动态代理的底层原理

2.需求

首先我们先有一个接口叫UserService,接口中有一个save的保存方法

public interface UserService {  
   
    public abstract void save();  
  
}  

接着我们给这个接口一个实现类叫UserServiceImpl实现save的保存方法

public class UserServiceImpl implements UserService {  
    
    public void save() {  
        System.out.println("保存方法....");  
    }  
}  

3.实现代码

那么接下来我的需求就是要对这个UserServiceImpl里面的目标方法save方法进行增强,如何增强呢,我们先使用jdk提供的动态代理来进行编写增强,代码实现下:

public class Demo{
  
  @Test
  public void test1()
  {
    	final UserServiceImpl userServiceImpl=new UserServiceImpl();
    	
 		UserService userProxy= (UserServive)Proxy.newProxyInstance(userServiceImpl.getClass().getClassLoader(), 
         					 userServiceImpl.getClass().getInterfaces(),
                               new InvocationHandler()new InvocationHandler() {
			
			@Override
			public Object invoke(Object proxy, Method method, Object[] args) 
             {
				System.out.println("保存方法之前增强...");  
				return method.invoke(userServiceImpl, args);
              	 System.out.println("保存方法之后增强...");
			}
		});
    
    userProxy.save();
  }
}

4.源码解析

执行以上代码会发现,对于UserServiceImpl对象的save保存方法确实进行了前后的增强, 用起来是比较简单,但是如果能知道它背后做了些什么手脚,那就更好不过了。首先来看一下JDK是怎样生成代理对象的。既然生成代理对象是用的Proxy类的静态方newProxyInstance,那么我们就去它的源码里看一下它到底都做了些什么?

// loader:类加载器
// interfaces:目标对象实现的接口
//h:InvocationHandler的实现类 
public static Object newProxyInstance(ClassLoader loader,     
                      Class<?>[] interfaces,    						
        	InvocationHandler h)throws IllegalArgumentException{   
        // 这里如果没有传递InvocationHandler的实现类就抛空指针
  		if (h == null) {  
            throw new NullPointerException();  
   		 }  
  		// 这里会返回代理对象字节码文件
    	Class cl = getProxyClass(loader, interfaces); 
  
  	  	// 调用代理对象的构造方法  
        Constructor cons = cl.getConstructor(constructorParams);  
         // 生成代理类的实例并把InvocationHandler的实例传给它的构造方法  
        return (Object) cons.newInstance(new Object[] { h }); 

Class cl = getProxyClass(loader, interfaces); 这句代码会返回代理对象字节码文件

我们可以看一看它是如何返回的

public static Class<?> getProxyClass0(ClassLoader loader,   
                                         Class<?>... interfaces)  
    throws IllegalArgumentException  
    {  
    // 如果目标类实现的接口数大于65535个则抛出异常  
    if (interfaces.length > 65535) {  
        throw new IllegalArgumentException("interface limit exceeded");  
    }  
    
     // 如果没有 声明代理对象所代表的Class类型
    Class proxyClass = null; 
    // 申明一个数组用来表示实现的接口数
    String[] interfaceNames = new String[interfaces.length];  
    // 声明一个集合
    Set interfaceSet = new HashSet();
   
   // 遍历目标类所实现的接口  
    for (int i = 0; i < interfaces.length; i++) {  
          
        // 拿到目标类实现的接口的名称  
        String interfaceName = interfaces[i].getName();  
        Class interfaceClass = null;  
        try {  
        // 加载目标类实现的接口到内存中   
        interfaceClass = Class.forName(interfaceName, false, loader);  
        } catch (ClassNotFoundException e) {  
        }  
        if (interfaceClass != interfaces[i]) {  
        throw new IllegalArgumentException(  
            interfaces[i] + " is not visible from class loader");  
        }    
        // 把目标类实现的接口代表的Class对象放到Set中 
        interfaceSet.add(interfaceClass);  
  
        interfaceNames[i] = interfaceName;  
    }  
    // 把目标类实现的接口名称作为缓存(Map)中的key   
    Object key = Arrays.asList(interfaceNames);  
  
    Map cache;  
      
    synchronized (loaderToCache) {  
        // 获取map  
        cache = (Map) loaderToCache.get(loader);  
        if (cache == null) {  
        // 如果获取不到,则新建地个HashMap实例  
        cache = new HashMap();  
        // 把HashMap实例和当前加载器放到缓存中  
        loaderToCache.put(loader, cache);  
        }  
  
    }  
    synchronized (cache) {  
        do {  
        // 根据接口的名称从map中获取对象  
        Object value = cache.get(key);  
        if (value instanceof Reference) {  
            proxyClass = (Class) ((Reference) value).get();  
        }  
        if (proxyClass != null) {  
            // 如果代理对象的Class实例已经存在,则直接返回  
            return proxyClass;  
        } else if (value == pendingGenerationMarker) {  
            try {  
            cache.wait();  
            } catch (InterruptedException e) {  
            }  
            continue;  
        } else {  
            cache.put(key, pendingGenerationMarker);  
            break;  
        }  
        } while (true);  
    }  
  
    try {     
        byte[] proxyClassFile = ProxyGenerator.generateProxyClass(  
            proxyName, interfaces);  
        try {  
            // 创建代理的Class对象  
            proxyClass = defineClass0(loader, proxyName,  
            proxyClassFile, 0, proxyClassFile.length);  
        } catch (ClassFormatError e) {  
            throw new IllegalArgumentException(e.toString());  
        }  
        }  
        proxyClasses.put(proxyClass, null);  
  
    }       
    return proxyClass;  
    }  

5.总结

通过以上的源码分析,我们可以看到newProxyInstance的底层首先会判断有没有接收到InvocationHandler的实现类,如果没有就会抛空指针,如果有就调用Class cl = getProxyClass(loader, interfaces)方法返回代理对象字节码文件,在这个方法中对代理类的接口做了个数限制并且还维护了一个代理类的缓存集合,如果有缓存就直接返回,否则就通过ProxyClassFactory去创建,ProxyClassFactory是Proxy的一个静态内部类,在这个静态内部类中会调用一个ProxyGenerator.generateProxyClass的方法,这个方法的内部生成了class文件,然后返回在通过cl.getConstructor(constructorParams)方法反射构造器生成了代理对象,到这里我们就能看到代理对象是如何产生出来的,希望以上的代码分析能够帮助我们学习动态代理…

数据中心机房是现代信息技术的核心设施,它承载着企业的重要数据和服务,因此,其基础设计与规划至关重要。在制定这样的方案时,需要考虑的因素繁多,包括但不限于以下几点: 1. **容量规划**:必须根据业务需求预测未来几年的数据处理和存储需求,合理规划机房的规模和设备容量。这涉及到服务器的数量、存储设备的容量以及网络带宽的需求等。 2. **电力供应**:数据中心是能源消耗大户,因此电力供应设计是关键。要考虑不间断电源(UPS)、备用发电机的容量,以及高效节能的电力分配系统,确保电力的稳定供应并降低能耗。 3. **冷却系统**:由于设备密集运行,散热问题不容忽视。合理的空调布局和冷却系统设计可以有效控制机房温度,避免设备过热引发故障。 4. **物理安全**:包括防火、防盗、防震、防潮等措施。需要设计防火分区、安装烟雾探测和自动灭火系统,设置访问控制系统,确保只有授权人员能进入。 5. **网络架构**:规划高速、稳定、冗余的网络架构,考虑使用光纤、以太网等技术,构建层次化网络,保证数据传输的高效性和安全性。 6. **运维管理**:设计易于管理和维护的IT基础设施,例如模块化设计便于扩展,集中监控系统可以实时查看设备状态,及时发现并解决问题。 7. **绿色数据中心**:随着环保意识的提升,绿色数据中心成为趋势。采用节能设备,利用自然冷源,以及优化能源管理策略,实现低能耗和低碳排放。 8. **灾难恢复**:考虑备份和恢复策略,建立异地灾备中心,确保在主数据中心发生故障时,业务能够快速恢复。 9. **法规遵从**:需遵循国家和地区的相关法律法规,如信息安全、数据保护和环境保护等,确保数据中心的合法运营。 10. **扩展性**:设计时应考虑到未来的业务发展和技术进步,保证机房有充足的扩展空间和升级能力。 技术创新在数据中心机房基础设计及规划方案中扮演了重要角色。例如,采用虚拟化技术可以提高硬件资源利用率,软件定义网络(SDN)提供更灵活的网络管理,人工智能和机器学习则有助于优化能源管理和故障预测。 总结来说,一个完整且高效的数据中心机房设计及规划方案,不仅需要满足当前的技术需求和业务目标,还需要具备前瞻性和可持续性,以适应快速变化的IT环境和未来可能的技术革新。同时,也要注重经济效益,平衡投资成本与长期运营成本,实现数据中心的高效、安全和绿色运行。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值