黑马程序员:Java基础总结----静态代理模式&动态代理

时间:2022-09-13 07:44:05
黑马程序员:Java基础总结



静态代理模式&动态代理

 
ASP.Net+Android+IO开发

.Net培训
、期待与您交流!




静态代理模式
public 
class 
Ts {
       
public 
static 
void 
main(String[] args) 
throws 
Exception {
             
// 通过中介公司生产一批衣服
            ClothingProduct cp = 
new 
ProxCompany(
new 
LiNingCompany());
            cp.productClothing();
      }

}

/**
 * 定义生产一批衣服功能的接口
 *
 */
interface 
ClothingProduct {

       
void 
productClothing(); 
// 有生产一批衣服的功能

}

/**
 *
 * 代理类:中介公司
 *
 */
class 
ProxCompany 
implements 
ClothingProduct {

       
private 
ClothingProduct 
cp 

// 中介公司不会生产衣服,需要找一家真正能生产衣服的公司

      ProxCompany(ClothingProduct cp) {
             
super
();
             
this
.
cp 
= cp;
      }

       
@Override
       
public 
void 
productClothing() {

            System. 
out
.println(
"收取1000块钱的中介费" 
);
             
cp
.productClothing();

      }

}

/**
 *
 * 李宁公司是生产服装的目标类
 *
 */
class 
LiNingCompany 
implements 
ClothingProduct {

       
@Override
       
public 
void 
productClothing() {

            System. 
out
.println(
"生产一批衣服。。。。" 
);
      }

}

上面程序的做法,使用的模式是静态代理模式

静态代理模式在现实编程中的弊端:

它的特征是代理类和目标对象的类都是在编译期间确定下来的,不利于程序上的扩展,上面示例中,如果客户还想找一个“生产一批鞋子”的工厂,那么还需要新增加一个代理类和一个目标类。如果客户还需要很多其他的服务,就必须一一的添加代理类和目标类。那就需要写很多的代理类和目标类


动态代理技术


java.lang.reflect
类 Proxy

Proxy 提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类。

构造方法摘要
protected Proxy(InvocationHandler h)
          使用其调用处理程序的指定值从子类(通常为动态代理类)构建新的 Proxy 实例。
字段摘要
protected  InvocationHandler h
          此代理实例的调用处理程序。
方法摘要
static InvocationHandler getInvocationHandler(Object proxy)
          返回指定代理实例的调用处理程序。
static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces)
          返回代理类的 java.lang.Class 对象,并向其提供类加载器和接口数组。
static boolean isProxyClass(Class<?> cl)
          当且仅当指定的类通过 getProxyClass 方法或 newProxyInstance 方法动态生成为代理类时,返回 true。
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
          返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。

每个代理实例都具有一个关联的调用处理程序。对代理实例调用方法时,将对方法调用进行编码并将其指派到它的调用处理程序的 invoke 方法。

public interface InvocationHandler 方法摘要
 Object invoke(Object proxy, Method method, Object[] args)
          在代理实例上处理方法调用并返回结果。
参数:
proxy - 在其上调用方法的代理实例
method - 对应于在代理实例上调用的接口方法的 
Method 实例。
Method 对象的声明类将是在其中声明方法的接口,该接口可以是代理类赖以继承方法的代理接口的超接口。
args - 包含传入代理实例上方法调用的参数值的对象数组,如果接口方法不使用参数,则为 
null。基本类型的参数被包装在适当基本包装器类(如 
java.lang.Integer 或 
java.lang.Boolean)的实例中。
返回:
从代理实例的方法调用返回的值。如果接口方法的声明返回类型是基本类型,则此方法返回的值一定是相应基本包装对象类的实例;否则,它一定是可分配到声明返回类型的类型。如果此方法返回的值为 
null 并且接口方法的返回类型是基本类型,则代理实例上的方法调用将抛出 
NullPointerException。否则,如果此方法返回的值与上述接口方法的声明返回类型不兼容,则代理实例上的方法调用将抛出 
ClassCastException

import 
java.lang.reflect.InvocationHandler;
import 
java.lang.reflect.Method;
import 
java.lang.reflect.Proxy;
import 
java.util.ArrayList;
import 
java.util.Collection;

public 
class 
Ts {
       
public 
static 
void 
main(String[] args) 
throws 
Exception {
             ArrayList test = 
new 
ArrayList();
             
// 代理只可以强转换成接口
             Collection list = (Collection ) getProxy(test, 
new 
MyAdvice());
             list.add(123);
             list.add(123);
            System. 
out
.println(list);

      }

       
public 
static 
Object getProxy(
final 
Object target, 
final 
Advice adv)
/* 终态是因为内部类调用 */ 
{
             
// 返回一个指定接口的代理类实例 obj
            Object obj = Proxy. newProxyInstance(
             
// 定义代理类的类加载器
                        target.getClass().getClassLoader(),
                         
// 代理类要实现的接口列表
                        target.getClass().getInterfaces(),
                         
// 指派方法调用的调用处理程序 InvocationHandler
                         
new 
InvocationHandler() {

                               
@Override
                               
public 
Object invoke(Object proxy, Method method,
                                          Object[] args) 
throws 
Throwable {                         
                                    adv.begintime(method);
                                     
//target目标 ,args方法参数,调用原来的方法
                                    Object retVal = method.invoke(target, args);
                                    adv.endtime(method);
                                     
return 
retVal;
                              }
                        });

             
return 
obj;
      }
}
//插入的建议接口
interface 
Advice {
       
void 
begintime(Method method);

       
void 
endtime(Method method);
}
//我的建议
class 
MyAdvice 
implements 
Advice {

       
@Override
       
public 
void 
begintime(Method method) {
            Long time = System. currentTimeMillis();
            System. 
out
.println(method.getName() + time);
      }

       
@Override
       
public 
void 
endtime(Method method) {
            Long time = System. currentTimeMillis();
            System. 
out
.println(method.getName() + time);
      }

}

一个更巧妙的方法:自定义一个处理程序
public 
class 
Ts {
       
public 
static 
void 
main(String[] args) 
throws 
Exception {
            ProxyHandler handler= 
new 
ProxyHandler();
             ClothingProduct cp2=(ClothingProduct)handler.newProxyInstance( 
new 
LiNingCompany());
            cp2.productClothing();

      }

}

class 
ProxyHandler 
implements 
InvocationHandler {

       
/* 目标对象 */
       
private 
Object 
target 
;

       
/* 创建目标对象的代理对象 */
       
public 
Object newProxyInstance(Object target) {

             
this
.
target 
= target;

             
/*
             * 第一个参数:定义代理类的类加载器
             * 第二个参数:代理类要实现的接口 列表
             * 第三个参数:指派方法调用的调用处理程序
             */
             
return 
Proxy.newProxyInstance(
this

target
.getClass().getClassLoader(),
                         
this
.
target 
.getClass().getClasses(), 
this
);

      }

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

            Object result = 
null
;

            System. 
out
.println(
"目标对象上的方法调用之前可以添加其他代码。。。" 
);
            result = method.invoke( 
this
.
target 
, args); 
// 通过反射调用目标对象上的方法
            System. 
out
.println(
"目标对象上的方法调用之后可以添加其他代码。。。" 
);

             
return 
result;
      }

}





 
ASP.Net+Android+IO开发

.Net培训
、期待与您交流!

黑马程序员:Java基础总结----静态代理模式&动态代理的更多相关文章

  1. 黑马程序员----java基础笔记中(毕向东)

    <p>------<a href="http://www.itheima.com" target="blank">Java培训.Andr ...

  2. 黑马程序员——JAVA基础之简述设计模式

    ------- android培训.java培训.期待与您交流! ---------- 设计模式(Design Patterns) 设计模式(Design pattern)是一套被反复使用.多数人知晓 ...

  3. 黑马程序员Java基础班&plus;就业班课程笔记全发布(持续更新)

    正在黑马学习,整理了一些课程知识点和比较重要的内容分享给大家,也是给自己拓宽一些视野,仅供大家交流学习,大家有什么更好的内容可以发给我 ,现有黑马教程2000G  QQ 1481135711 这是我总 ...

  4. 黑马程序员----java基础笔记上(毕向东)

    ------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- 笔记一共记录了毕向东的java基础的25天课程,分上.中.下 本片为上篇,涵盖前10天课程 1. ...

  5. 黑马程序员&lowbar;java基础笔记&lpar;13&rpar;&period;&period;&period;类加载器和代理

    —————————— ASP.Net+Android+IOS开发..Net培训.期待与您交流! —————————— 1,类加载器.2,代理. 1,类加载器. Java虚拟机中可以安装多个类加载器,系 ...

  6. 黑马程序员——JAVA基础之泛型和通配符

    ------- android培训.java培训.期待与您交流! ---------- 泛型:            JDK1.5版本以后出现新特性.用于解决安全问题,是一个类型安全机制. 泛型好处: ...

  7. 黑马程序员——JAVA基础之简述面向对象,类,变量,匿名对象

    ------- android培训.java培训.期待与您交流! ---------- 面向对象: 面向对象是相对面向过程而言 面向对象和面向过程都是一种思想 面向过程 强调的是功能行为 面向对象 将 ...

  8. 黑马程序员——JAVA基础之语法、命名规则

    ------- android培训.java培训.期待与您交流! ---------- 1.java语言组成:关键字,标识符,注释,常量和变量,运算符,语句,函数,数组. 2.java关键字:被Jav ...

  9. 黑马程序员——JAVA基础之主函数main和静态static,静态代码块

    ------- android培训.java培训.期待与您交流! ---------- 主函数:是一个特殊的函数.作为程序的入口,可以被jvm调用. 主函数的定义: public:代表着该函数访问权限 ...

  10. 黑马程序员——JAVA基础之多线程的安全问题

    ------- android培训.java培训.期待与您交流! ---------- 导致多线程出现问题的一个特殊的状态:就绪.具备了执行资格,但是还没有获取资源. 导致安全问题的出现的原因: 1. ...

随机推荐

  1. spring注解源码分析--how does autowired works?

    1. 背景 注解可以减少代码的开发量,spring提供了丰富的注解功能.我们可能会被问到,spring的注解到底是什么触发的呢?今天以spring最常使用的一个注解autowired来跟踪代码,进行d ...

  2. Spark之SQL解析(源码阅读十)

    如何能更好的运用与监控sparkSQL?或许我们改更深层次的了解它深层次的原理是什么.之前总结的已经写了传统数据库与Spark的sql解析之间的差别.那么我们下来直切主题~ 如今的Spark已经支持多 ...

  3. iOS学习10之OC类和对象

    本次是OC的第一节课,主要是学习和理解类与对象 1.面向对象 1> OOP(Object Oriented Programming)面向对象编程. 面向对象以事物为中心,完成某件事情都需要哪些事 ...

  4. RAC 环境下参数文件&lpar;spfile&rpar;管理

    RAC环境下,初始化参数文件与但实例下参数文件有些异同,主要表现在初始化参数可以为多个实例公用,也可以单独设置各个实例的初始化参数.对于那些非共用的初始化参数则必须要单独设置,而共用的则可以单独设置, ...

  5. Dnsmasq(局域网DNS,DHCP)

    安装:yum -y install dnsmasq   dnsmasq配置文件: /etc/dnsmasq.conf 默认指定DNS服务器(优先级)文件:/etc/resolv.conf 默认host ...

  6. Linux epoll总结

    Linux epoll总结 Linux  epoll epoll是Kernel 2.6后新加入的事件机制,在高并发条件下,远优于select.epoll最大的好处在于它不会随着监听fd数目的增长而降低 ...

  7. &quot&semi;The Application was unable to start correctly &lpar;0xc000007b&rpar;&period; Click OK to close the application&quot&semi;

    我有时将MFC编译成64位并运行,就会报这个错误. 后来查找原因,就在于系统中使用了错误的dll.比如这个程序要使用64位的dll,而你拷贝进去的是同名的32位dll.解决方法就是放置正确的dll. ...

  8. margin、padding单位百分比

    年前做了一个测试题 https://www.wenjuan.com/s/VjaEva/,里面有一道题目涉及到了margin和padding单位为百分比的情况.写出来记录一下以防止自己忘记. <! ...

  9. Java基础笔记(1)----语言基础

    变量 变量:是内存中的一块存储空间,是存储数据的基本单元. 使用:先声明,后赋值,在使用. 声明:数据类型 + 变量名 = 值.(例:int a = 5:) 数据类型 分类:如图: 详解: Strin ...

  10. 给linux服务器添加一块新的磁盘

    http://www.linuxidc.com/Linux/2011-02/31868.htm 把硬盘装好后,我们用 fdisk -l 查看下: 图中可以看出 /dev/sdb 是500G,新加的硬盘 ...