1.何为代理
  代理,即代替主角完成一些额外的事情。例如,明星都有经纪人,明星参演电影之前,经纪人作为明星的代理人和出资方洽谈片酬、排期等,而真正参与拍戏的还是明星本人,明星拍完戏后,由经纪人代理明星去清算片酬等。Java中的代理机制就是在目标方法执行前后执行一些额外的操作,如安全检查、记录日志等,Java中的代理分为静态代理和动态代理。

2.静态代理
  首先看一下静态代理,直接上代码,代码模拟了登录操作。

public interface LoginService {
void login();
}
public class LoginServiceImpl implements LoginService {
@Override
public void login() {
System.out.println("login");
}
}
public class LoginServiceProxy implements LoginService {
private LoginService loginService;
public LoginServiceProxy(LoginService loginService) {
this.loginService = loginService;
}
@Override
public void login() {
beforeLogin();
loginService.login();
afterLogin();
}
private void beforeLogin() {
System.out.println("before login");
}
private void afterLogin() {
System.out.println("after login");
}
}
public class Client {
@Test
public void test() {
LoginService loginService = new LoginServiceImpl();
LoginService loginServiceProxy = new LoginServiceProxy(loginService);
loginServiceProxy.login();
}
}

输出结果如下:

before login
login
after login

上面代码实现的静态代理很容易理解,使用聚合方式,在登录操作前后执行额外的操作。静态代理方式可以看得到具体代理类的代码,且代码由程序员编写,在编译之后会生成相应的class文件。使用静态代理方式的缺点,如果需要对LoginService接口中有N个方法都代理,则需要在代理类中创建N个代理方法,并且需要编写重复的代理操作代码。

3.概念解释
  目标接口,即对目标操作的抽象,如LoginService。
  目标类,即目标接口的实现类,如LoginServiceImpl。
  目标对象,即目标类的实例。
  代理类,即目标类的代理,如LoginServiceProxy。
  代理对象,即代理类的实例。

4.动态代理
  动态代理,即在运行时根据目标接口动态生成的代理类。动态代理方式生成的代理类在编译后不会生成实际的class文件,而是在运行时动态生成类字节码,并加载到JVM中使用。下面使用JDK的动态代理机制模拟登录操作,具体代码如下。

public interface LoginService {
void login();
}
public class LoginServiceImpl implements LoginService {
@Override
public void login() {
System.out.println("login");
}
}
public class ProxyInvocationHandler implements InvocationHandler {
private LoginService loginService;
public ProxyInvocationHandler(LoginService loginService) {
this.loginService = loginService;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
beforeLogin();
Object invokeResult = method.invoke(loginService, args);
afterLogin();
return invokeResult;
}
private void beforeLogin() {
System.out.println("before login");
}
private void afterLogin() {
System.out.println("after login");
}
}
public class Client {
@Test
public void test() {
LoginService loginService = new LoginServiceImpl();
ProxyInvocationHandler proxyInvocationHandler = new ProxyInvocationHandler(loginService);
LoginService loginServiceProxy = (LoginService) Proxy.newProxyInstance(loginService.getClass().getClassLoader(), loginService.getClass().getInterfaces(), proxyInvocationHandler);
loginServiceProxy.login();
createProxyClassFile();
}
public static void createProxyClassFile() {
String name = "LoginServiceProxy";
byte[] data = ProxyGenerator.generateProxyClass(name, new Class[]{LoginService.class});
try {
FileOutputStream out = new FileOutputStream("/Users/" + name + ".class");
out.write(data);
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}

  输出结果如下。

before login
login
after login

  JDK动态代理方式实现代理的步骤如下:
  1.编写目标接口;
  2.编写目标类实现目标接口,实现目标方法的具体逻辑;
  3.编写一个代理处理器类实现InvocationHandler接口,重写invoke方法,用于指定运行时将生成的代理类需要完成的具体操作,包括beforeLogin和afterLogin。代理对象调用任何代理方法时都会调用这个invoke方法;
  4.创建代理对象,使用代理对象调用代理方法。

  上面的步骤中主要涉及以下两个类:java.lang.reflect.InvocationHandler和java.lang.reflect.Proxy。InvocationHandler是一个接口,代理类的调用处理器,每个代理对象都具有一个关联的调用处理器,用于指定动态生成的代理类需要完成的具体操作。该接口中有一个invoke方法,代理对象调用任何目标接口的方法时都会调用这个invoke方法,在这个方法中进行目标类的目标方法的调用。Proxy提供静态方法用于创建动态代理类和代理类实例,同时,使用它提供的方法创建的代理类都是它的子类。这个类中主要关注newProxyInstance方法,该方法用于创建代理类对象,方法声明如下:

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

loader参数用于指示使用哪个类加载器加载这个代理类;interfaces表示代理类实现的接口列表;h表示使用哪个调用处理器。

  后续文章《深入浅出JDK动态代理(二)》会深入源码分析JDK动态代理生成的代理类是什么样,为什么调用代理类的任何方法时都一定会调用invoke方法,值得期待!

  

深入浅出JDK动态代理(一)的更多相关文章

  1. JDK动态代理实例

    最近看<深入浅出MyBatis技术原理与实战>这本书时,里面讲到Mapper接口的内部实现是通过JDK动态代理生成实现类,联想到之前看<SPRING技术内幕>这本书里也常常提到 ...

  2. JDK动态代理

    一.基本概念 1.什么是代理? 在阐述JDK动态代理之前,我们很有必要先来弄明白代理的概念.代理这个词本身并不是计算机专用术语,它是生活中一个常用的概念.这里引用维基百科上的一句话对代理进行定义: A ...

  3. 静态代理和利用反射形成的动态代理(JDK动态代理)

    代理模式 代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问.在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用. 静态代理 1.新建 ...

  4. Spring中的JDK动态代理

    Spring中的JDK动态代理 在JDK1.3以后提供了动态代理的技术,允许开发者在运行期创建接口的代理实例.在Sun刚推出动态代理时,还很难想象它有多大的实际用途,现在动态代理是实现AOP的绝好底层 ...

  5. AOP学习心得&jdk动态代理与cglib比较

    什么是AOP AOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善.OOP引入 ...

  6. JDK动态代理的实现原理

    学习JDK动态代理,从源码层次来理解其实现原理参考:http://blog.csdn.net/jiankunking/article/details/52143504

  7. Java中的JDK动态代理

    所谓代理,其实就是相当于一个中间人,当客户端需要服务端的服务时,不是客户直接去找服务,而是客户先去找代理,告诉代理需要什么服务,然后代理再去服务端找服务,最后将结果返回给客户. 在日常生活中,就拿买火 ...

  8. JDK动态代理与CGLib动态代理

    1.JDK动态代理 JDK1.3以后java提供了动态代理技术,允许开发者在运行期创建接口的代理实例,动态代理是实现AOP的绝好底层技术. JDK的动态代理主要涉及到java.lang.reflect ...

  9. jdk动态代理实现

    1.jdk动态代理的简单实现类 package com.proxy; import java.lang.reflect.InvocationHandler; import java.lang.refl ...

随机推荐

  1. 接口测试及Postman工具

    首先,什么是接口呢? 接口一般来说有两种,一种是程序内部的接口,一种是系统对外的接口.系统对外的接口:比如你要从别的网站或服务器上获取资源或信息,别人肯定不会把数据库共享给你,他只能给你提供一个他们写 ...

  2. matlab学习GUI的基本操作

    在命令行窗口输入guide 单击确定后出现,可以选择控件来设计,然后可以保存 右击可以查看控件的所有属性 举一个简单的GUI实例---实现数据的传输 添加可编辑文本框 更改字体大小,string默认的 ...

  3. vj线段树专题

    vj线段树专题题解 单点更新模板 void build(int x,int l,int r){//sum[x]控制l-r区域 if(l==r){Sum[x]=num[l];return ;} int ...

  4. 解决value toDF is not a member of org.apache.spark.rdd.RDD (spark2.1 )

    解决上述办法有两点: 1.两个import 需要放在 hiveCtx之后. val hiveCtx: SparkSession = SparkSession.builder.config(conf). ...

  5. WEBGL学习【四】模型视图矩阵

    <html lang="zh-CN"> <!--服务器运行地址:http://127.0.0.1:8080/webgl/LearnNeHeWebGL/NeHeWe ...

  6. 训练1-V

    输入2个正整数A,B,求A与B的最大公约数. Input 2个数A,B,中间用空格隔开.(1<= A,B <= 10^9) Output 输出A与B的最大公约数. Sample Input ...

  7. MySQL导入到SQLServer

    Mysql是在Linux环境服务器,MSSQL在windows服务器上 1.在MSServer中安装VPN 2.为VPN配置Mysql服务器账号 3.账号中的文件 4.在MSSQL服务器上安装mysq ...

  8. Java 接口技术 Interface

    一.什么是接口技术(Interface): //举例中Comparable是一个接口,Employee是一个类 1.接口不是类,而是对类的一组描述,并不给出每个类的具体实现. 2.一个类可以实现多个接 ...

  9. Ajax发送GET和POST请求案例

    使用ajax实现菜单联动 通常情况下,GET请求用于从服务器上获取数据,POST请求用于向服务器发送数据. 需求:选择第一个下拉框的值,根据第一个下拉框的值显示第二个下拉框的值 首先使用GET方式. ...

  10. C# 知识点集合

    1.一个Visual studio软件进程只能打开一个程序集,但是一个程序集可以加载多个项目,通过程序集的添加功能可以实现. 2.F11单步调试,F10跨程序调试(一般用不到) 3.VS如何快速的切换 ...