Java动态代理学习
动态代理类
Java动态代理类位于java.lang.reflect包下,一般主要涉及到以下两个类:
1.Interface InvocationHandler
该接口中仅定义了一个方法:
Object invoke(Object proxy, Method method, Object[] args)
在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,如上例中的request(),args为该方法的参数数组(无参时设置为null)。
这个抽象方法在代理类中动态实现。
2.Proxy
该类即为动态代理类,作用类似于上文例子中的ProxySubject,其中主要包含如下内容:
protected Proxy(InvocationHandler h): 构造函数,用于给内部的invocation handler赋值。
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,由它接管实际的工作。
在使用动态代理类时,我们必须实现InvocationHandler接口。每一个动态代理类都会有一个与之关联的invocation handler。
真正的调用是在invocation handler的invoke()方法里完成的。
动态代理步骤
1.创建一个实现接口InvocationHandler的类,它必须实现invoke()方法。
2.创建被代理的类以及接口。
3.通过Proxy的静态方法newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)创建一个代理。
4.通过代理调用方法。
动态代理例子1:
首先定义抽象角色和真实角色类:
public interface Subject
{
public void request();
}

public class RealSubject implements Subject
{
@Override
public void request()
{
System.out.println("From real subject!");
}
}

之后定义一个DynamicSubject类:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method; /**
* 该代理类的内部属性是Object类型,实际使用的时候通过该类的构造方法传递进来一个对象。
* 该类实现了invoke()方法,该方法中的method.invoke()其实就是调用被代理对象的将要执行的方法,
* 方法参数sub表示该方法从属于sub。
* 通过动态代理类,我们可以在执行真实对象的方法前后加入自己的一些额外方法
*
*/
public class DynamicSubject implements InvocationHandler
{ //对真实对象的引用
private Object sub; public DynamicSubject(Object obj)
{
this.sub = obj; } @Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable
{
System.out.println("Before calling: " + method); //通过反射来调用方法
method.invoke(sub, args); System.out.println("After calling: " + method);
return null;
} }

使用的时候:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy; public class Client
{
public static void main(String[] args)
{
RealSubject realSubject = new RealSubject(); InvocationHandler handler = new DynamicSubject(realSubject); Class<?> classType = handler.getClass(); // 生成代理
// 动态生成一个类(实现了指定的接口),生成类的对象,转换成接口类型
Subject subject = (Subject) Proxy.newProxyInstance(classType
.getClassLoader(), realSubject.getClass().getInterfaces(),
handler); subject.request();
// 调用方法时,转移给handler接管,由其中的invoke()方法实际完成方法执行 System.out.println(subject.getClass());// 打印出:class $Proxy0
// $Proxy0是在运行期间动态生成的一个类 } }

通过这种方式,被代理的对象(RealSubject)可以在运行时动态改变,需要控制的接口(Subject接口)可以在运行时改变,控制的方式(DynamicSubject类)也可以动态改变,从而实现了非常灵活的动态代理关系。
动态代理实现例子2:
这个例子中定义了一个接口:
public interface Foo
{
public void doAction();
}
这个接口有两个实现类:

public class FooImpl1 implements Foo
{
@Override
public void doAction()
{
System.out.println("From Implement 1 !");
}
} public class FooImpl2 implements Foo
{
@Override
public void doAction()
{
System.out.println("From Implement 2 !");
}
}

定义invocation handler,其中的set方法使得实际对象是可更换的:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method; public class CommonInvocationHandler implements InvocationHandler
{
private Object target; public CommonInvocationHandler()
{ } public CommonInvocationHandler(Object obj)
{
this.target = obj;
} public void setTarget(Object target)
{
this.target = target;
} @Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable
{
return method.invoke(target, args);
} }

使用:

import java.lang.reflect.Proxy; public class Demo
{
public static void main(String[] args)
{
CommonInvocationHandler handler = new CommonInvocationHandler(); Foo f = null; handler.setTarget(new FooImpl1()); f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
new Class[] { Foo.class }, handler); f.doAction();
System.out.println("----------------------------");
handler.setTarget(new FooImpl2());
f.doAction(); } }

程序运行后输出:
From Implement 1 !
----------------------------
From Implement 2 !
动态代理实现例子3:
1、BookFacade.java
public interface BookFacade {
public void addBook();
}
2、BookFacadeImpl.java
public class BookFacadeImpl implements BookFacade {
@Override
public void addBook() {
System.out.println("增加图书方法。。。");
}
}
3、BookFacadeProxy.java
package net.battier.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* JDK动态代理代理类
*
* @author student
*
*/
public class BookFacadeProxy implements InvocationHandler {
private Object target;
/**
* 绑定委托对象并返回一个代理类
* @param target
* @return
*/
public Object bind(Object target) {
this.target = target;
//取得代理对象
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this); //要绑定接口(这是一个缺陷,cglib弥补了这一缺陷)
}
@Override
/**
* 调用方法
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result=null;
System.out.println("事物开始");
//执行方法
result=method.invoke(target, args);
System.out.println("事物结束");
return result;
}
}4、TestProxy.java
package net.battier.test;
import net.battier.dao.BookFacade;
import net.battier.dao.impl.BookFacadeImpl;
import net.battier.proxy.BookFacadeProxy;
public class TestProxy {
public static void main(String[] args) {
BookFacadeProxy proxy = new BookFacadeProxy();
BookFacade bookProxy = (BookFacade) proxy.bind(new BookFacadeImpl());
bookProxy.addBook();
}
}
但是,JDK的动态代理依靠接口实现,如果有些类并没有实现接口,则不能使用JDK代理,这就要使用cglib动态代理了。
Cglib动态代理
JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。
示例
1、BookFacadeCglib.java
package net.battier.dao;
public interface BookFacade {
public void addBook();
}
2、BookCadeImpl1.java
package net.battier.dao.impl;
/**
* 这个是没有实现接口的实现类
*
* @author student
*
*/
public class BookFacadeImpl1 {
public void addBook() {
System.out.println("增加图书的普通方法...");
}
}
3、BookFacadeProxy.java
package net.battier.proxy;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
* 使用cglib动态代理
*
* @author student
*
*/
public class BookFacadeCglib implements MethodInterceptor {
private Object target;
/**
* 创建代理对象
*
* @param target
* @return
*/
public Object getInstance(Object target) {
this.target = target;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.target.getClass());
// 回调方法
enhancer.setCallback(this);
// 创建代理对象
return enhancer.create();
}
@Override
// 回调方法
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
System.out.println("事物开始");
proxy.invokeSuper(obj, args);
System.out.println("事物结束");
return null;
}
}
4、TestCglib.java
package net.battier.test;
import net.battier.dao.impl.BookFacadeImpl1;
import net.battier.proxy.BookFacadeCglib;
public class TestCglib {
public static void main(String[] args) {
BookFacadeCglib cglib=new BookFacadeCglib();
BookFacadeImpl1 bookCglib=(BookFacadeImpl1)cglib.getInstance(new BookFacadeImpl1());
bookCglib.addBook();
}
}
Java动态代理学习的更多相关文章
- Java动态代理学习【Spring AOP基础之一】
Spring AOP使用的其中一个底层技术就是Java的动态代理技术.Java的动态代理技术主要围绕两个类进行的 java.lang.reflect.InvocationHandler java.la ...
- JAVA 动态代理学习记录
打算用JAVA实现一个简单的RPC框架,看完RPC参考代码之后,感觉RPC的实现主要用到了两个方面的JAVA知识:网络通信和动态代理.因此,先补补动态代理的知识.---多看看代码中写的注释 参考:Ja ...
- java 动态代理学习(Proxy,InvocationHandler)
前几天看到java的动态代理机制,不知道是啥玩意,然后看了看.死活不知道 invoke(Object proxy, Method m, Object[] args)种的proxy是个什么东西,放在这里 ...
- CgLib动态代理学习【Spring AOP基础之一】
如果不了解JDK中proxy动态代理机制的可以先查看上篇文章的内容:Java动态代理学习[Spring AOP基础之一] 由于Java动态代理Proxy.newProxyInstance()的时候会发 ...
- java 动态代理深度学习(Proxy,InvocationHandler),含$Proxy0源码
java 动态代理深度学习, 一.相关类及其方法: java.lang.reflect.Proxy,Proxy 提供用于创建动态代理类和实例的静态方法.newProxyInstance()返回一个指定 ...
- Java 动态代理机制详解
在学习Spring的时候,我们知道Spring主要有两大思想,一个是IoC,另一个就是AOP,对于IoC,依赖注入就不用多说了,而对于Spring的核心AOP来说,我们不但要知道怎么通过AOP来满足的 ...
- java高级---->Java动态代理的原理
Java动态代理机制的出现,使得 Java 开发人员不用手工编写代理类,只要简单地指定一组接口及委托类对象,便能动态地获得代理类.代理类会负责将所有的方法调用分派到委托对象上反射执行,在分派执行的过程 ...
- java动态代理实现与原理详细分析
关于Java中的动态代理,我们首先需要了解的是一种常用的设计模式--代理模式,而对于代理,根据创建代理类的时间点,又可以分为静态代理和动态代理. 一.代理模式 代理模式是常用的java设计模式, ...
- java动态代理实现与原理详细分析(代码层面解释了AOP的实现)
关于Java中的动态代理,我们首先需要了解的是一种常用的设计模式--代理模式,而对于代理,根据创建代理类的时间点,又可以分为静态代理和动态代理. 一.代理模式 代理模式是常用的java设计模式, ...
随机推荐
- JVM学习网址(收集总结)
1.文章分类 - JVM调优总结 JVM综合调优汇总 星火燎原智勇 2018-08-16 11:11 阅读:8 评论:0 JVM调优04-概括总结 星火燎原智勇 2017-01-08 23:28 ...
- sys模块 常用函数
sys模块是和python解释器打交道的 sys.argv 命令行参数List,第一个元素是程序本身路径 sys.exit(n) 退出程序,正常退出时exit(0),错误退出sys.exit(1) s ...
- 使用JSON实现分页
使用JSON实现分页可直接用 Fenye.html <!DOCTYPE html> <html> <head> <title>JSON分页</ti ...
- js-权威指南学习笔记10
第十章 正则表达式的模式匹配 1.正则表达式是一个描述字符模式的对象. 2.可以使用RegExp()构造函数来创建RegExp对象,不过RegExp对象更多是通过一种特殊的直接量语法来创建. 3.程序 ...
- Docker for Windows(四)实践搭建&删除MySQL服务
我们已经下载安装好了Docker for Windows:Docker for Windows(一)下载与安装,也简单了解了Docker常用命令:Docker for Windows(三)Docker ...
- react组件直接在document上添加事件
demo:比如组件里有个div写的框框,点击document body的背景色变红,点击div写的框框没效果 componentDidMount(){ document.onclick = this. ...
- linux 获取命令或配置文件的帮助信息 man、whatis、apropos、--help
man /usr/bin/man man [命令或配置文件]获取帮助信息 man ls /-lman date/-d man services //不需要添加绝对路径/etc/services NAM ...
- java 标准输出流、标准错误输出流、标准输入流及扫描仪
初步认识标准输出流.错误输出流.输入流.扫描仪 package com.mydemo.controller; import java.util.Scanner; public class HelloW ...
- CSS 小结笔记之盒子模型
网页标签可以看成是一个个盒子,页面设计就像垒积木一样,在网页中将盒子摆好显示出来.在浏览器中可以很清楚的去看到一个标签的盒子,具体方法如下: 打开浏览器的开发人员工具,在Elements中选中一个标签 ...
- C# 中 DataTable 使用详解。
在项目中经常用到DataTable,如果DataTable使用得当,不仅能使程序简洁实用,而且能够提高性能,达到事半功倍的效果,现对DataTable的使用技巧进行一下总结. 一.DataTable简 ...