1.
问题
在许多情况下,我们需要使用代理模式来解决问题。如下为代理模式的类图。
如下为使用
Java
实现代理模式的一个例子:
package com.demo.dynamicproxy;
public interface IHello {
public void sayHello() ;
}
package com.demo.dynamicproxy;
public class HelloProxy implements IHello {
private IHello speaker = new HelloSpeaker();
public HelloProxy(IHello hello) {
this.speaker = hello;
}
private void preRequest() {
System.out.println("prepare");
}
private void postRequest() {
System.out.println("applaud");
}
@Override
public void sayHello() {
preRequest();
this.speaker.sayHello();
postRequest();
}
}
package com.demo.dynamicproxy;
/**
* @author Xiechangming
*
*/
public class HelloSpeaker implements IHello {
@Override
public void sayHello() {
System.out.println("Hello,world");
}
}
package com.demo.dynamicproxy;
public class ProxyTest {
public static void main(String...args){
//static proxy
HelloProxy proxy = new HelloProxy(new HelloSpeaker());
proxy.sayHello();
//dynamic proxy
HelloHandler handler = new HelloHandler();
IHello dynamicProxy = (IHello)handler.bind(new HelloSpeaker());
dynamicProxy.sayHello();
}
}
正如你所见,需要显示地实现一个代理类,这就是静态代理模式。
如果需要被代理的方法很多,且代理的逻辑相同,势必要为每种方法实现一个代理类,在程序规模稍大是就会产生很多代理类。该如何解决呢?
2.
解决方案
在
JDK1.3
中,引入了动态代理类,用来解决相同的代理逻辑可以为多种被代理类重复使用。
JDK
动态代理中包含一个类和一个接口:
InvocationHandler
接口:
public interface InvocationHandler {
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable;
}
参数说明:
Object proxy
:指被代理的对象。
Method method
:要调用的方法
Object[] args
:方法调用时所需要的参数
该方法就是实现代理逻辑的地方,类似于
ProxySubject
。
Proxy
类:
Proxy
类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类,此类提供了如下的操作方法:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
参数说明:
ClassLoader loader
:类加载器
Class<?>[] interfaces
:得到全部的接口
InvocationHandler h
:得到
InvocationHandler
接口的子类实例
该方法返回真实的代理类的一个对象,该代理类是
JDK
动态生成的。如下是一个动态代理模式的实例:
package com.demo.dynamicproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class HelloHandler implements InvocationHandler {
private Object delegate;
public Object bind(Object delegate) {
this.delegate = delegate;
return Proxy.newProxyInstance(delegate.getClass().getClassLoader(), delegate.getClass().getInterfaces(), this);
}
private void preRequest() {
System.out.println("prepare");
}
private void postRequest() {
System.out.println("applaud");
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
preRequest();
method.invoke(this.delegate, args);
postRequest();
return null;
}
}
package com.demo.dynamicproxy;
public class ProxyTest {
public static void main(String...args){
//static proxy
HelloProxy proxy = new HelloProxy(new HelloSpeaker());
proxy.sayHello();
//dynamic proxy
HelloHandler handler = new HelloHandler();
IHello dynamicProxy = (IHello)handler.bind(new HelloSpeaker());
dynamicProxy.sayHello();
}
}
3.
实现原理
通过查看
Proxy
的源代码,可以对动态代理模式的实现原理有一个大致的了解
:
下面是
newProxyInstance
的实现,从中可以看出关键是调用
getProxyClass
方法
获得最终的代理类,该代理类是动态生成
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
if (h == null) {
throw new NullPointerException();
}
/*
* Look up or generate the designated proxy class.
*/
Class cl = getProxyClass(loader, interfaces);
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
Constructor cons = cl.getConstructor(constructorParams);
return (Object) cons.newInstance(new Object[] { h });
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString());
} catch (IllegalAccessException e) {
throw new InternalError(e.toString());
} catch (InstantiationException e) {
throw new InternalError(e.toString());
} catch (InvocationTargetException e) {
throw new InternalError(e.toString());
}
}
下面是
getProxyClass
的主要实现
public static Class<?> getProxyClass(ClassLoader loader,
Class<?>... interfaces)
throws IllegalArgumentException
{
…
Class proxyClass = null;//声明要动态生成的类
…
String proxyName = proxyPkg + proxyClassNamePrefix + num; //定义动态生成的类的名字
/*
* Verify that the class loader hasn't already
* defined a class with the chosen name.
*/
/*
* Generate the specified proxy class.
*/
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces);//调用generateProxyClass方法生成动态类的.class文件的二进制,Sun的内部实现
try {
proxyClass = defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);//.class文件的二进制导入到JVM,获得类的实例。这是一个本地方法。
} catch (ClassFormatError e) {
/*
* A ClassFormatError here means that (barring bugs in the
* proxy class generation code) there was some other
* invalid aspect of the arguments supplied to the proxy
* class creation (such as virtual machine limitations
* exceeded).
*/
throw new IllegalArgumentException(e.toString());
}
}
// add to set of all generated proxy classes, for isProxyClass
proxyClasses.put(proxyClass, null);
}
…
return proxyClass;//返回生成的类。
}
4.
不足
该代理模式要求被代理的类必须要实现接口,如果被代理的类没有实现接口,则不能使用动态代理模式。那么有什么更好的方式来代理没有实现接口的类的方法呢?这就要用到开源软件
CBLib
了。下面是是使用
CGLib
实现的例子:
package com.demo.dynamicproxy;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class CglibProxy implements MethodInterceptor {
private void preRequest() {
System.out.println("prepare");
}
private void postRequest() {
System.out.println("applaud");
}
public Object newProxyInstance(Object target) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
preRequest();
proxy.invokeSuper(obj, args);
postRequest();
return null;
}
}
package com.demo.dynamicproxy;
public class ProxyTest {
public static void main(String... args) {
// // static proxy
// HelloProxy proxy = new HelloProxy(new HelloSpeaker());
//
// proxy.sayHello();
//
// // dynamic proxy
// HelloHandler handler = new HelloHandler();
//
// IHello dynamicProxy = (IHello) handler.bind(new HelloSpeaker());
//
// dynamicProxy.sayHello();
// Cglib
CglibProxy cglibProxy = new CglibProxy();
IHello helloProxy = (IHello)cglibProxy.newProxyInstance(new HelloSpeaker());
helloProxy.sayHello();
}
}
CGLib
本质上是动态生成了一个被代理类的子类,并
Override
了被代理的方法,因此被代理的类中方法不能将方法定义为
final
,否则就类似于直接对被代理类的调用,就如实例中,只会输出“Hello,world"。
- 大小: 13.5 KB
分享到:
相关推荐
Java动态代理实现AOP Java动态代理是实现Aspect Oriented Programming(AOP)的重要手段。在Java中,动态代理可以通过java.lang.reflect InvocationHandler接口和java.lang.reflect.Proxy类来实现。AOP的主要思想...
### Java动态代理实现AOP详解 #### 一、引言 随着软件开发复杂度的提升,传统的面向对象编程(OOP)已经难以满足现代软件工程的需求。为了更好地管理跨切面的关注点,如日志记录、性能监控、安全控制等,面向切面...
总的来说,Java动态代理实现数据源连接池的核心思想是利用`InvocationHandler`来拦截对数据库操作的调用,通过代理对象在每次操作前后进行连接的获取和释放,从而实现连接池的逻辑。这种方式虽然相比现成的连接池库...
### Java动态代理实现数据库连接池 #### 背景与挑战 在开发应用程序时,数据库连接池是一个常用且重要的组成部分。频繁地建立和断开数据库连接不仅效率低下,还可能导致性能瓶颈。为了解决这一问题,引入了数据库...
下面我们将详细探讨如何使用Java动态代理实现委托模式,以及相关的源码和工具应用。 首先,理解委托模式的基本概念。委托模式通常由三部分组成:委托者(Delegate)、被委托者(Subject)和客户端(Client)。委托...
Java 动态代理是Java平台提供的一种强大的工具,它允许我们在运行时动态生成代理类,这些代理类可以实现一组指定的接口,同时还能在方法调用前后添加自定义的行为。这种机制大大简化了面向切面编程(AOP)和事件监听...
### 使用Java动态代理实现一个简单的网络请求拦截器 #### 一、引言 在软件开发过程中,为了增强程序的功能或方便进行调试与监控,我们常常需要在不改变原有业务逻辑的基础上,添加一些额外的行为(如日志记录、...
在本场景中,我们将探讨如何使用Java动态代理结合注解来实现日志拦截,以便在调用方法时记录相关的日志信息。 首先,让我们了解Java动态代理的基本概念。在Java中,动态代理主要由两个类实现:`java.lang.reflect....
Java中的动态代理是通过`java.lang.reflect.Proxy`类和`java.lang.reflect.InvocationHandler`接口实现的。Proxy类用于创建动态代理实例,而InvocationHandler接口则定义了调用处理程序的逻辑,即当代理对象的方法被...
- `设计模式:用Java动态代理实现AOP.docx`可能包含了如何使用Java动态代理来实现设计模式,尤其是代理模式,以达到AOP的效果。 - `Spring AOP入门实例详解.docx`可能涵盖了Spring AOP的基本概念、配置以及如何...
Java提供了两种主要的动态代理实现方式:JDK动态代理和CGLIB动态代理。 **JDK动态代理**: JDK动态代理基于接口实现,也就是说,被代理的对象必须实现至少一个接口。代理机制的核心是`java.lang.reflect.Proxy`类和...
在深入探讨Java动态代理的实现过程之前,我们首先需要理解动态代理的基本概念及其在Java中的应用价值。动态代理,顾名思义,是在运行时动态创建代理对象的一种机制,它无需在编译期就确定代理类的具体实现,而是通过...
在本文中,我们将深入探讨这两个关键组件以及如何使用它们来实现动态代理。 ### 1. Java动态代理的基本概念 动态代理允许我们在运行时创建一个实现了特定接口的新类。这个新类(代理类)可以代理原始类(目标类)...