动态代理



注意下面内容可能会引起你的不适


先幽默一下吧:

改错了一行代码的后果

程序员祈求运行通过的样子



男朋友写代码不理我,于是我悄悄改掉了web.xml的一个配置,他搞了两天都没调通,我告诉了他,结果他要和我分手,我很伤心,但他的朋友告诉我,他没砍死你才说明他真的爱你…”

“楼主别tm编了,程序员哪来的女朋友!”

“谁告诉你我是女的了。”
~~~~~

>>>>>>>>>>>>

Proxy

    Proxy代理模式是一种结构型设计模式,主要解决的问题是:在直接访问对象时带来的问题.

   代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问。代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。

 

                      

    为了保持行为的一致性,代理类和委托类通常会实现相同的接口,所以在访问者看来两者没有丝毫的区别。通过代理类这中间一层,能有效控制对委托类对象的直接访问,也可以很好地隐藏和保护委托类对象,同时也为实施不同控制策略预留了空间,从而在设计上获得了更大的灵活性。

更通俗的说,代理解决的问题当两个类需要通信时,引入第三方代理类,将两个类的关系解耦,让我们只了解代理类即可,而且代理的出现还可以让我们完成与另一个类之间的关系的统一管理,但是切记,代理类和委托类要实现相同的接口,因为代理真正调用的还是委托类的方法。

 

使用场合举例:

如果需要委托类处理某一业务,那么我们就可以先在代理类中统一处理然后在调用具体实现类

按照代理的创建时期,代理类可以分为两种: 

静态:由程序员创建代理类或特定工具自动生成源代码再对其编译。在程序运行前代理类的.class文件就已经存在了。

动态:在程序运行时运用反射机制动态创建而成。

 

引入动态代理: 

根据如上的介绍,你会发现静态代理的每个代理类只能为一个接口服务,这样程序开发中必然会产生许多的代理类

所以我们就会想办法可以通过一个代理类完成全部的代理功能,那么我们就需要用动态代理

 

在上面的示例中,一个代理只能代理一种类型,而且是在编译器就已经确定被代理的对象。而动态代理是在运行时,通过反射机制实现动态代理,并且能够代理各种类型的对象

 

Java中要想实现动态代理机制,需要java.lang.reflect.InvocationHandler接口和 java.lang.reflect.Proxy 类的支持

 

 

下面用案例来说明

 

接口

public interface UserService {

    String find(String name);

}

 

 

 

实现类

public class UserServiceImpl implements UserService {

 

    @Override

        public String find(String name) {

        System.out.println("========find==========" + name);

      return "女朋友";

}

 

}

 

 

代理工厂

public class ProxyFactory {

 

            public static UserService getProxyInstance(final UserServiceImpl target) throws Throwable{

            /**

             * 第一个参数:类加载器

             * 第二个参数:目标对象所实现的接口

             * 第三个参数:目标对象方法调用监听器

             */

            return (UserService)JavaProxy.newProxyInstance(target.getClass().getClassLoader(),

            target.getClass().getInterfaces(), new InvocationHandler(){

            

            @Override

            public Object invoke(Method method, Object[] args) throws Throwable {

                System.out.println("=====调用目标方法之前======");

                

                Object obj = method.invoke(target, args);

                System.out.println("返回值" + obj );

                System.out.println("=====调用目标方法之后======");

                return obj;

                }

                });

                }

            

            }

 

下面的是支持的类,这是一个老师写的,有利于我们理解底层的原理

下面的类是最终生成一个实现UserService接口的类,通过代码控制编译

支持的类

接口

public interface InvocationHandler {


        public Object invoke(Method method, Object[] params) throws Throwable;

}

 

public class JavaProxy {


        public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,

        InvocationHandler handler) throws Throwable{

        

        Class<?> inter = interfaces[0];

        StringBuilder res = new StringBuilder();

        // 生成的java类名

        String javaClassName= "$_" + UUID.randomUUID().toString().replaceAll("-""_");

        res.append("@SuppressWarnings({ \"unchecked\", \"rawtypes\", \"unused\"})\n");

        res.append("public class " + javaClassName);

        res.append(" implements " + inter.getName() + "{\n\n");

        // 定义InvocationHandler属性

        res.append("\tprivate " + InvocationHandler.class.getName() + " handler;\n");

        res.append("\tpublic " + javaClassName + "(" + InvocationHandler.class.getName() + " handler){\n");

        res.append("\t\tthis.handler = handler;\n");

        res.append("\t}\n");

        // 获取所有的方法

        Method[] methods = inter.getDeclaredMethods();

        for (Method method : methods){

        // 获取方法返回值类型

        String returnTypeName = method.getReturnType().getCanonicalName();

        boolean isReturn = false;

        if (!"void".equals(returnTypeName)){

        isReturn = true;

        }

        

        res.append("\n\tpublic " + returnTypeName);

        res.append(" " + method.getName() + "(");

        // 获取参数类型

        Class<?>[] parameterTypes = method.getParameterTypes();

        // 方法名中间加参数

        String paramNames = "";

        for (int i = 0; i < parameterTypes.length; i++){

        Class<?> parameterType = parameterTypes[i];

        res.append(i == 0 ? parameterType.getCanonicalName() + " param" + i

              : ", " + parameterType.getCanonicalName() + " param" + i);

        paramNames += i == 0 ? "param" + i : ", param" + i;

        }

        res.append(") {\n");

        

        // ----------方法体实现开始------

        res.append("\t\ttry{\n");

        res.append("\t\t\t" + Method.class.getName() + " method = ");

        res.append(inter.getName() + ".class.getMethod(\"" + method.getName() +"\"");

        for (Class<?> parameterType : parameterTypes){

        res.append(", " + parameterType.getCanonicalName() + ".class");

        }

        res.append(");\n");

        res.append("\t\t\tObject obj = handler.invoke(method, new Object[]{"+ paramNames +"});\n");

        // 判断是否有返回值

        if (isReturn){

        res.append("\t\t\treturn (" + returnTypeName + ")obj;\n");

        }

        // 加异常catch

        res.append("\t\t}catch(Throwable ex){\n");

        res.append("\t\t\tthrow new RuntimeException(ex);\n");

        res.append("\t\t}\n");

        // ----------方法体实现结束------

        res.append("\n\t}");

        }

        res.append("\n}");

        

        // 动态生成Java类

        String fileName = javaClassName + ".java";

        File file = new File(fileName);

        FileWriter fw = new FileWriter(file);

        fw.write(res.toString());

        fw.flush();

        fw.close();

        

        // java编译

        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

        StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null,nullnull);

        compiler.getTask(null, fileMgr, nullnullnull, fileMgr.getJavaFileObjects(fileName)).call();

        fileMgr.flush();

        fileMgr.close();

        // 编译成Class后删除源文件

        //file.delete();

        

        // 加载编译后的Class

        String dir = System.getProperty("user.dir");

        URL[] urls = {new URL("file:/" + dir + "/")};

        URLClassLoader ul = new URLClassLoader(urls);

        Class<?> cls = ul.loadClass(javaClassName);

        Constructor<?> cs = cls.getConstructor(InvocationHandler.class);

        File classFile = new File(javaClassName + ".class");

        // 删除Class文件

        classFile.delete();

        return cs.newInstance(handler);

        }

        }

        

        生成的代码

  @SuppressWarnings({ "unchecked""rawtypes""unused"})

        public class $_38a5c89c_e0e4_46c1_8b2b_8bc84398f014implements cn.itcast.proxy.UserService{

         

        private cn.itcast.proxy.support.InvocationHandler handler;

        public $_38a5c89c_e0e4_46c1_8b2b_8bc84398f014(cn.itcast.proxy.support.InvocationHandler handler){

        this.handler = handler;

        }

         

        public java.lang.String find(java.lang.String param0) {

        try{

        java.lang.reflect.Method method = cn.itcast.proxy.UserService.class.getMethod("find", java.lang.String.class);

        Object obj = handler.invoke(method, new Object[]{param0});

        return (java.lang.String)obj;

        }catch(Throwable ex){

        throw new RuntimeException(ex);

        }

         

}

}

 


 

测试类

public class FindTest {

 

/**

 * @param args

 * @throws Throwable

 */

public static void main(String[] args) throws Throwable {

UserService us1 = ProxyFactory.getProxyInstance(new UserServiceImpl());


System.out.println(us1.find("李小三")); //调用的是代理对象的invoke方法

}

 

}

 

最终结果为

 

希望对你有帮助,想要完整代码可以加我微信号:D1175639137

注意下面内容可能会引起你的不适
先幽默一下吧:

改错了一行代码的后果

程序员祈求运行通过的样子



男朋友写代码不理我,于是我悄悄改掉了web.xml的一个配置,他搞了两天都没调通,我告诉了他,结果他要和我分手,我很伤心,但他的朋友告诉我,他没砍死你才说明他真的爱你…”

“楼主别tm编了,程序员哪来的女朋友!”

“谁告诉你我是女的了。”
~~~~~

>>>>>>>>>>>>

Proxy

    Proxy代理模式是一种结构型设计模式,主要解决的问题是:在直接访问对象时带来的问题.

   代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问。代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理。

 

                      

    为了保持行为的一致性,代理类和委托类通常会实现相同的接口,所以在访问者看来两者没有丝毫的区别。通过代理类这中间一层,能有效控制对委托类对象的直接访问,也可以很好地隐藏和保护委托类对象,同时也为实施不同控制策略预留了空间,从而在设计上获得了更大的灵活性。

更通俗的说,代理解决的问题当两个类需要通信时,引入第三方代理类,将两个类的关系解耦,让我们只了解代理类即可,而且代理的出现还可以让我们完成与另一个类之间的关系的统一管理,但是切记,代理类和委托类要实现相同的接口,因为代理真正调用的还是委托类的方法。

 

使用场合举例:

如果需要委托类处理某一业务,那么我们就可以先在代理类中统一处理然后在调用具体实现类

按照代理的创建时期,代理类可以分为两种: 

静态:由程序员创建代理类或特定工具自动生成源代码再对其编译。在程序运行前代理类的.class文件就已经存在了。

动态:在程序运行时运用反射机制动态创建而成。

 

引入动态代理: 

根据如上的介绍,你会发现静态代理的每个代理类只能为一个接口服务,这样程序开发中必然会产生许多的代理类

所以我们就会想办法可以通过一个代理类完成全部的代理功能,那么我们就需要用动态代理

 

在上面的示例中,一个代理只能代理一种类型,而且是在编译器就已经确定被代理的对象。而动态代理是在运行时,通过反射机制实现动态代理,并且能够代理各种类型的对象

 

Java中要想实现动态代理机制,需要java.lang.reflect.InvocationHandler接口和 java.lang.reflect.Proxy 类的支持

 

 

下面用案例来说明

 

接口

public interface UserService {

    String find(String name);

}

 

 

 

实现类

public class UserServiceImpl implements UserService {

 

    @Override

        public String find(String name) {

        System.out.println("========find==========" + name);

      return "女朋友";

}

 

}

 

 

代理工厂

public class ProxyFactory {

 

            public static UserService getProxyInstance(final UserServiceImpl target) throws Throwable{

            /**

             * 第一个参数:类加载器

             * 第二个参数:目标对象所实现的接口

             * 第三个参数:目标对象方法调用监听器

             */

            return (UserService)JavaProxy.newProxyInstance(target.getClass().getClassLoader(),

            target.getClass().getInterfaces(), new InvocationHandler(){

            

            @Override

            public Object invoke(Method method, Object[] args) throws Throwable {

                System.out.println("=====调用目标方法之前======");

                

                Object obj = method.invoke(target, args);

                System.out.println("返回值" + obj );

                System.out.println("=====调用目标方法之后======");

                return obj;

                }

                });

                }

            

            }

 

下面的是支持的类,这是一个老师写的,有利于我们理解底层的原理

下面的类是最终生成一个实现UserService接口的类,通过代码控制编译

支持的类

接口

public interface InvocationHandler {


        public Object invoke(Method method, Object[] params) throws Throwable;

}

 

public class JavaProxy {


        public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,

        InvocationHandler handler) throws Throwable{

        

        Class<?> inter = interfaces[0];

        StringBuilder res = new StringBuilder();

        // 生成的java类名

        String javaClassName= "$_" + UUID.randomUUID().toString().replaceAll("-""_");

        res.append("@SuppressWarnings({ \"unchecked\", \"rawtypes\", \"unused\"})\n");

        res.append("public class " + javaClassName);

        res.append(" implements " + inter.getName() + "{\n\n");

        // 定义InvocationHandler属性

        res.append("\tprivate " + InvocationHandler.class.getName() + " handler;\n");

        res.append("\tpublic " + javaClassName + "(" + InvocationHandler.class.getName() + " handler){\n");

        res.append("\t\tthis.handler = handler;\n");

        res.append("\t}\n");

        // 获取所有的方法

        Method[] methods = inter.getDeclaredMethods();

        for (Method method : methods){

        // 获取方法返回值类型

        String returnTypeName = method.getReturnType().getCanonicalName();

        boolean isReturn = false;

        if (!"void".equals(returnTypeName)){

        isReturn = true;

        }

        

        res.append("\n\tpublic " + returnTypeName);

        res.append(" " + method.getName() + "(");

        // 获取参数类型

        Class<?>[] parameterTypes = method.getParameterTypes();

        // 方法名中间加参数

        String paramNames = "";

        for (int i = 0; i < parameterTypes.length; i++){

        Class<?> parameterType = parameterTypes[i];

        res.append(i == 0 ? parameterType.getCanonicalName() + " param" + i

              : ", " + parameterType.getCanonicalName() + " param" + i);

        paramNames += i == 0 ? "param" + i : ", param" + i;

        }

        res.append(") {\n");

        

        // ----------方法体实现开始------

        res.append("\t\ttry{\n");

        res.append("\t\t\t" + Method.class.getName() + " method = ");

        res.append(inter.getName() + ".class.getMethod(\"" + method.getName() +"\"");

        for (Class<?> parameterType : parameterTypes){

        res.append(", " + parameterType.getCanonicalName() + ".class");

        }

        res.append(");\n");

        res.append("\t\t\tObject obj = handler.invoke(method, new Object[]{"+ paramNames +"});\n");

        // 判断是否有返回值

        if (isReturn){

        res.append("\t\t\treturn (" + returnTypeName + ")obj;\n");

        }

        // 加异常catch

        res.append("\t\t}catch(Throwable ex){\n");

        res.append("\t\t\tthrow new RuntimeException(ex);\n");

        res.append("\t\t}\n");

        // ----------方法体实现结束------

        res.append("\n\t}");

        }

        res.append("\n}");

        

        // 动态生成Java类

        String fileName = javaClassName + ".java";

        File file = new File(fileName);

        FileWriter fw = new FileWriter(file);

        fw.write(res.toString());

        fw.flush();

        fw.close();

        

        // java编译

        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

        StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null,nullnull);

        compiler.getTask(null, fileMgr, nullnullnull, fileMgr.getJavaFileObjects(fileName)).call();

        fileMgr.flush();

        fileMgr.close();

        // 编译成Class后删除源文件

        //file.delete();

        

        // 加载编译后的Class

        String dir = System.getProperty("user.dir");

        URL[] urls = {new URL("file:/" + dir + "/")};

        URLClassLoader ul = new URLClassLoader(urls);

        Class<?> cls = ul.loadClass(javaClassName);

        Constructor<?> cs = cls.getConstructor(InvocationHandler.class);

        File classFile = new File(javaClassName + ".class");

        // 删除Class文件

        classFile.delete();

        return cs.newInstance(handler);

        }

        }

        

        生成的代码

  @SuppressWarnings({ "unchecked""rawtypes""unused"})

        public class $_38a5c89c_e0e4_46c1_8b2b_8bc84398f014implements cn.itcast.proxy.UserService{

         

        private cn.itcast.proxy.support.InvocationHandler handler;

        public $_38a5c89c_e0e4_46c1_8b2b_8bc84398f014(cn.itcast.proxy.support.InvocationHandler handler){

        this.handler = handler;

        }

         

        public java.lang.String find(java.lang.String param0) {

        try{

        java.lang.reflect.Method method = cn.itcast.proxy.UserService.class.getMethod("find", java.lang.String.class);

        Object obj = handler.invoke(method, new Object[]{param0});

        return (java.lang.String)obj;

        }catch(Throwable ex){

        throw new RuntimeException(ex);

        }

         

}

}

 


 

测试类

public class FindTest {

 

/**

 * @param args

 * @throws Throwable

 */

public static void main(String[] args) throws Throwable {

UserService us1 = ProxyFactory.getProxyInstance(new UserServiceImpl());


System.out.println(us1.find("李小三")); //调用的是代理对象的invoke方法

}

 

}

 

最终结果为

 

希望对你有帮助,想要完整代码可以加我微信号:D1175639137

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值