首页 文章 精选 留言 我的

精选列表

搜索[反射],共2899篇文章
优秀的个人博客,低调大师

java代理模式与反射机制

代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。 代理模式一般涉及到的角色有: 抽象角色:声明真实对象和代理对象的共同接口; 代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。 真实角色:代理角色所代表的真实对象,是我们最终要引用的对象。 一个简单的例子如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 package com.java.proxy; interface Subject{ abstract public void request(); } class RealSubject implements Subject{ @Override public void request() { System.out.println( "real subject" ); } } class ProxySubject implements Subject{ Subject subject; public ProxySubject() { } public ProxySubject(Subject subject){ this .subject=subject; } @Override public void request() { System.out.println( "预处理工作" ); subject.request(); System.out.println( "后续工作" ); } } public class ProxyModel { public static void main(String[] args) { Subject subject= new ProxySubject( new RealSubject()); subject.request(); } } 由以上代码可以看出,客户实际需要调用的是RealSubject类的request()方法,现在用ProxySubject来代理 RealSubject类,同样达到目的,同时还可以封装其他方法(可以做一些预处理,和后续工作),可以处理一些其他问题。 另外,如果要按照上述的方法使用代理模式,那么真实角色必须是事先已经存在的,并将其作为代理对象的内部属性。但是实际使用时,一个真实角色必须 对应一个代理角色,如果大量使用会导致类的急剧膨胀;此外,如果事先并不知道真实角色,该如何使用代理呢?这个问题可以通过Java的动态代理类来解决。 动态代理 Java动态代理类位于Java.lang.reflect包下,一般主要涉及到以下两个类: (1).Interface InvocationHandler:该接口中仅定义了一个方法Object:invoke(Object obj,Method method, Object[] args)。在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,如上例中的request(),args为该方法的参数数组。 这个抽象方法在代理类中动态实现。 (2).Proxy:该类即为动态代理类,作用类似于上例中的ProxySubject,其中主要包含以下内容: Protected Proxy(InvocationHandler h):构造函数,估计用于给内部的h赋值。 Static Class getProxyClass (ClassLoader loader, Class[] interfaces):获得一个代理类,其中loader是类装载器,interfaces是真实类所拥有的全部接口的数组。 Static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h):返回代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用被代理类的在Subject接口中声明过的方法)。 所谓Dynamic Proxy是这样一种class:它是在运行时生成的class,在生成它时你必须提供一组interface给它,然后该class就宣称它实现了这些 interface。你当然可以把该class的实例当作这些interface中的任何一个来用。当然啦,这个Dynamic Proxy其实就是一个Proxy,它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作 下面我们使用动态代理来改写上面的例子: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 package com.java.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; interface Subject{ abstract public void request(); } class RealSubject implements Subject{ public RealSubject() { } @Override public void request() { System.out.println( "real subject" ); } } class ProxySubject implements InvocationHandler{ private Subject obj; public ProxySubject() { } public ProxySubject(Subject obj){ this .obj=obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println( "预处理工作" ); method.invoke(obj, args); System.out.println( "后续工作" ); return null ; } } public class ProxyModel { public static void main(String[] args) { RealSubject realSubject= new RealSubject(); Class<?>cla=realSubject.getClass(); InvocationHandler handler= new ProxySubject(realSubject); Subject subject=(Subject)Proxy.newProxyInstance(cla.getClassLoader(), cla.getInterfaces(), handler); subject.request(); } } 最后我们给出一个在远程方法中使用代理的例子:因为代码很长,所以不打算在文章中粘贴代码了,我把项目上传到微盘了,下载地址为:http://vdisk.weibo.com/s/jax8z 项目的部署为: ============================================================================== 本文转自被遗忘的博客园博客,原文链接:http://www.cnblogs.com/rollenholt/archive/2012/11/28/2792779.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

Java反射 - 动态类加载和重载

可以使用Java在运行时加载和重新加载类,虽然它不像人们希望的那样简单。 本文将解释何时以及如何在Java中加载和重新加载类。 ClassLoader Java应用程序中的所有类都使用java.lang.ClassLoader的一些子类加载。 因此,动态加载类也必须使用java.lang.ClassLoader子类来完成。 当一个类被加载时,它所引用的所有类也被加载。 这个类加载模式是递归的,直到所有需要的类都被加载。 这可能不是应用程序中的所有类。 未引用的类只有在引用时才加载。 装载等级 Java中的类加载器被组织成一个层次结构。 当你创建一个新的标准的Java ClassLoader时,你必须提供一个父类的ClassLoader。 如果一个ClassLoader被要求加载一个类,它会要求它的父类加载器加载它。 如果父类加载器找不到该类,那么子类加载器将尝试自己加载它。 类加载 给定类加载器在加载类时使用的步骤如下: 检查类是否已经加载。 如果未加载,则请求父类加载器加载该类。 如果父类加载器无法加载类,请尝试将其加载到此类加载器中。 当你实现一个能够重新加载类的类加载器时,你将需要偏离这个序列。 父类加载器不应请求加载的类加载。详细情况请看Java的类加载机制(ClassLoader) 动态类加载 动态加载类很容易。 所有你需要做的就是获得一个ClassLoader并且调用它的loadClass()方法。 这里是一个例子: public class MainClass { public static void main(String[] args){ ClassLoader classLoader = MainClass.class.getClassLoader(); try { Class aClass = classLoader.loadClass("com.jenkov.MyClass"); System.out.println("aClass.getName() = " + aClass.getName()); } catch (ClassNotFoundException e) { e.printStackTrace(); } } 动态类重载 动态类重新加载有点更具挑战性。 Java的内置Class加载器在加载之前总是检查一个类是否已经被加载。 因此,使用Java的内置类加载器不能重新加载类。 重新加载一个类,你将不得不实现你自己的ClassLoader子类。 即使使用ClassLoader的自定义子类,也是一个挑战。 每个加载的类都需要链接。 这是使用ClassLoader.resolve()方法完成的。 这个方法是final的,因此不能在你的ClassLoader子类中重写。 resolve()方法将不允许任何给定的ClassLoader实例连接两次相同的类。 因此,每次你想重新加载一个类,你都必须使用ClassLoader子类的一个新实例。 这不是不可能的,但是在设计类重新加载时需要知道。 设计类重新加载 如前所述,您不能使用已经加载该类的ClassLoader重载一个类。 因此,您将不得不使用不同的ClassLoader实例重新加载类。 但是这带来了很多新的挑战。 加载到Java应用程序中的每个类都由其完全限定的名称(包名称+类名称)和加载它的ClassLoader实例标识。 这意味着,类加载器A加载的类MyObject与加载类加载器B的MyObject类不是同一个类。请看下面的代码: MyObject object = (MyObject)myClassReloadingFactory.newInstance("com.jenkov.MyObject"); 注意代码中MyObject类是如何作为对象变量的类型引用的。这会导致MyObject类被加载了该代码所在的类的同一个类加载器加载。 如果myClassReloadingFactory对象工厂使用与上面的代码所在的类不同的类加载器重新加载MyObject类,则不能将重新加载的MyObject类的实例转换为对象变量的MyObject类型。由于两个MyObject类用不同的类加载器加载,因此即使它们具有相同的完全限定类名,它们也被视为不同的类。尝试将一个类的对象转换为另一个类的引用将导致ClassCastException。 有可能解决此限制,但您将不得不以两种方式之一更改您的代码: 使用一个接口作为变量类型,并重新加载实现类。 使用父类作为变量类型,并重新加载一个子类。 这是两个相应的代码示例: MyObjectInterface object =(MyObjectInterface)myClassReloadingFactory.newInstance("com.jenkov.MyObject"); MyObjectSuperclass object = (MyObjectSuperclass)myClassReloadingFactory.newInstance("com.jenkov.MyObject"); 如果在重载实现类或子类时变量的类型(接口或超类)没有重载,则这两种方法都可以工作。 为了使这个工作,你当然需要实现你的类加载器,让父类加载接口或父类。 当你的类加载器被要求加载MyObject类时,它也会被要求加载MyObjectInterface类或者MyObjectSuperclass类,因为这些类是从MyObject类中引用的。 您的类加载器必须将这些类的加载委托给加载包含接口或超类型变量的类的相同类加载器。 类加载器加载/重载的例子 上面的文字包含了很多的话题。 我们来看一个简单的例子。 下面是一个简单的ClassLoader子类的例子。 注意它是如何将类加载委派给它的父类,除了它可以重新加载的类之外。 如果将此类的加载委托给父类加载器,则以后无法重新加载。 请记住,一个类只能由相同的ClassLoader实例加载一次。 如前所述,这只是一个示例,用于向您展示ClassLoader行为的基础知识。你自己的类加载器可能不应该局限于一个类,而是你需要重新加载的类的集合。 另外,你也许不应该对类路径进行硬编码。 public class MyClassLoader extends ClassLoader{ public MyClassLoader(ClassLoader parent) { super(parent); } public Class loadClass(String name) throws ClassNotFoundException { if(!"reflection.MyObject".equals(name)) return super.loadClass(name); try { String url = "file:C:/data/projects/tutorials/web/WEB-INF/" + "classes/reflection/MyObject.class"; URL myUrl = new URL(url); URLConnection connection = myUrl.openConnection(); InputStream input = connection.getInputStream(); ByteArrayOutputStream buffer = new ByteArrayOutputStream(); int data = input.read(); while(data != -1){ buffer.write(data); data = input.read(); } input.close(); byte[] classData = buffer.toByteArray(); return defineClass("reflection.MyObject", classData, 0, classData.length); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return null; } } 下面是一个示例使用MyClassLoader。 public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException { ClassLoader parentClassLoader = MyClassLoader.class.getClassLoader(); MyClassLoader classLoader = new MyClassLoader(parentClassLoader); Class myObjectClass = classLoader.loadClass("reflection.MyObject"); AnInterface2 object1 = (AnInterface2) myObjectClass.newInstance(); MyObjectSuperClass object2 = (MyObjectSuperClass) myObjectClass.newInstance(); //创建新的类加载以至于能被重载 classLoader = new MyClassLoader(parentClassLoader); myObjectClass = classLoader.loadClass("reflection.MyObject"); object1 = (AnInterface2) myObjectClass.newInstance(); object2 = (MyObjectSuperClass) myObjectClass.newInstance(); } 这是使用类加载器加载的reflection.MyObject类。 注意它是如何扩展一个超类并实现一个接口的。 这仅仅是为了这个例子。 在你自己的代码中,你只需要其中的一个 - 扩展或实现。 public class MyObject extends MyObjectSuperClass implements AnInterface2{ //... 覆盖父类方法 // 或者实现接口方法 }

资源下载

更多资源
Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册