java实现简单的动态代理

来源:互联网 发布:ubuntu光盘安装教程 编辑:程序博客网 时间:2024/05/16 06:54

Java实现简单的动态代理

先写一个简单的例子来说明为什么需要代理。
    1.编写接口UserManager.java
package proxy;public interface UserManager {public void addUser(int id, String name, int age);public void deleteUser(int id);public String getUserName(int id);}
2.编写实现类UserManagerImpl.java
package proxy;public class UserManagerImpl implements UserManager {@Overridepublic void addUser(int id, String name, int age) {System.out.println("------------addUser()-----------");}@Overridepublic void deleteUser(int id) {System.out.println("------------deleteUser()-----------");}@Overridepublic String getUserName(int id) {System.out.println("------------getUserName()-----------");return null;}}
    3.编写客户端类Client.java对UserManager实现进行测试。
package proxy;public class Client {public static void main(String[] args) {// TODO Auto-generated method stubUserManager manager = new UserManagerImpl();manager.addUser(1, "zhangsan", 24);}}
     输出结果为------------addUser()-----------

    现在,想在所有UserManager函数调用之前,先对用户信息进行安全性检查,就需要在所有的函数执行前添加安全性检查,如代码UserManagerImpl.java所示。
package proxy;public class UserManagerImpl implements UserManager {@Overridepublic void addUser(int id, String name, int age) {security();System.out.println("------------addUser()-----------");}@Overridepublic void deleteUser(int id) {security();System.out.println("------------deleteUser()-----------");}@Overridepublic String getUserName(int id) {security();System.out.println("------------getUserName()-----------");return null;}private void security(){System.out.println("------------security()--------------");}}
    这样实现会打破程序设计的封装性,如果需要添加功能就需要需改程序的源代码,因此这里就需要使用代理的思想。
    增加一个代理,代理类可以控制原对象,所以在调用原对象之前就可以进行安全性检查。

    添加代理类UserManagerImplProxy.java
package proxy;public class UserManagerImplProxy implements UserManager {private UserManager manager;public UserManagerImplProxy(UserManager manager){this.manager = manager;}@Overridepublic void addUser(int id, String name, int age) {security();this.manager.addUser(id, name, age);}@Overridepublic void deleteUser(int id) {security();this.manager.deleteUser(id);}@Overridepublic String getUserName(int id) {security();return this.manager.getUserName(id);}private void security(){System.out.println("------------security()--------------");}}

    将实际对象通过构造函数传递给代理类,在调用实际对象方法前添加对安全性的检查security()方法,通过使用代理将需要添加的功能从UserMangerImpl类中分离出来
修改后的Client.java代码如下。
package proxy;public class Client {public static void main(String[] args) {// TODO Auto-generated method stub//UserManager manager = new UserManagerImpl();//manager.addUser(1, "zhangsan", 24);UserManager manager = new UserManagerImplProxy(new UserManagerImpl());manager.addUser(1, "zhangsan", 24);}}
    程序输出为------------security()--------------
      ------------addUser()-----------

    代理模式:在实际开发当中使用频率非常高的一种设计模式。
    定义:为其他对象提供一种代理机制以控制这个对象的访问。
    代理对象要与目标对象的接口一致。

    以上是简单代理的实现方式,在实际使用中,使用最多的是动态代理。代理对象会在运行期生成。

    编写安全性检查的处理方法类SecurityHandler.java
package proxy;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public class SecurityHandler implements InvocationHandler {private Object targerObject;public Object newProxyObject(Object targetObject){this.targerObject = targetObject;Object object = Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),<span style="white-space:pre"></span>targetObject.getClass().getInterfaces(),this);return object;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable {security();Object result = null;try{result = method.invoke(this.targerObject, args);}catch(Exception e){e.printStackTrace();}return result;}private void security(){System.out.println("------------security()--------------");}}
    下面对动态代理的实现进行说明
    1.需要实现InvocationHandler接口,并实现这个接口当中的invoke方法。当调用代理对象的方法的时会自动调用invoke方法,所以可以将安全性检查的方法放到invoke方法中,这样在调用目标对象的方法前就会调用security()方法了。
    2.在SecurityHandler方法中声明了一个Object类型的实例变量,用来存储目标对象。
    3.编写newProxyObject方法,这个方法将目标对象赋值给实例变量targerObject来保存目标对象。
    4.调用Proxy的newProxyInstance函数来创建一个代理对象,该函数有3个参数,分别是ClassLoader,接口数组(Class<?>[])以及一个InvocationHandler。
      JVM在加载类的时候就是通过调用ClassLoader的loadClass()方法来加载类的,而第二个参数是一个接口数组,这就是说明被代理的类需要实现某个接口,当然也可以不实现接口,使用CGLIB技术,这个技术不在本文讨论范围内。第三个参数是一个InvocationHandler,这里置为this即可。
    
    修改Client.java
package proxy;public class Client {public static void main(String[] args) {// TODO Auto-generated method stub//UserManager manager = new UserManagerImpl();//manager.addUser(1, "zhangsan", 24);//UserManager manager = new UserManagerImplProxy(new UserManagerImpl());//manager.addUser(1, "zhangsan", 24);SecurityHandler proxy = new SecurityHandler();<span style="white-space:pre"></span>UserManager manager = (UserManager)proxy.newProxyObject(new UserManagerImpl());<span style="white-space:pre"></span>manager.addUser(1, "zhangsan", 24);}}

    程序输出为------------security()--------------
            ------------addUser()-----------
    创建一个SecurityHandler对象,然后创建一个目标对象,调用newProxyObject函数获得这个对象的一个代理对象,再调用代理对象的方法,这样即可实现动态代理。

0 0
原创粉丝点击