在java中有两类代理模式,动态代理模式和静态代理模式,关于动态代理的实现,涉及到字节码的重新编写,无法单纯的通过java代码实现,不过jdk内置实现了动态代理模式,基于接口的,其它的有cglib,aspectJ等,这里不献丑了.
之所以有动态代理的出现,主要是因为静态代理不够灵活,这里相对传统的静态代理模式进行一下改进,使我们能方便快捷的使用代理的设计思想,同时有不需要大量冗余的代码.
话不多说,先看一个传统的代理模式的实现:
//接口
public interface HelloService {
void sayHello(String name);
}
//接口实现
public class HelloSerivceImpl implements HelloService{
@Override
public void sayHello(String name) {
Console.writeLine("Hi~,glad to meet U,"+name);
}
}
//代理实现
public class HelloServiceProxy implements HelloService{
private HelloService service;
public HelloServiceProxy(HelloService service){
this.service=service;
}
@Override
public void sayHello(String name) {
Method m=service.getClass().getDeclaredMethod("sayHello", String.class);
this.before(service, m, new Object[]{name});
service.sayHello(name);
this.before(service, m, new Object[]{name});
}
public void after(Object target, Method method, Object[] params) {
System.out.println(">>>>>>after the method of " + method.getName());
}
public void before(Object target, Method method, Object[] params) {
System.out.println(">>>>>>before the method of " + method.getName());
}
}
//测试
static void test_static(){
HelloService service=new HelloServiceProxy(new HelloSerivceImpl());
service.sayHello("lining");
}
从上面我们可以看,代理的接口实现实际上是调用接口实例的对应方法,并且在其执行之前调用before方法,在执行后调用after方法,从而实现拦截器的效果.但是当接口的方法很多的时候,我们需要对每个方法重复上面的过程,这将充满重复的代码段,增加我们的工作量,为此我们又必须对其进行改造和优化.
从上面我们可以看出,代码重复的地方在于before和after方法,而且两个方法是分开的,能想到的一个简单的改进方法就是将方法名作为参数传递过去,进行调用,于是我们这里抽象出来一个统一执行的方法:
public class HelloServiceProxy implements HelloService {
private HelloService service;
public HelloServiceProxy(HelloService service) {
this.service = service;
}
@Override
public void sayHello(String name) {
invoke("sayHello", name);
}
public void after(Object target, Method method, Object[] params) {
System.out.println(">>>>>>after the method of " + method.getName());
}
public void before(Object target, Method method, Object[] params) {
System.out.println(">>>>>>before the method of " + method.getName());
}
private Object invoke(String name, Object... params) {
Object result = null;
try {
Class<?>[] types = new Class[params.length];
for (int i = 0; i < types.length; types[i] = params[i++].getClass())
;
Method m = service.getClass().getDeclaredMethod(name, types);
this.before(service,m, params);
result = m.invoke(service, params);
this.after(service,m, params);
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
}
从上面的代码我们可以看到,比最初的模式有了一定的改进,所有调用接口的方法统一起来的,所不同的仅仅是传递参数的不同,然而,能不能更进一步的,毕竟传递的方法名称是硬编码的,即使写错了,编译器也检测不出来.如果能够有一种方法可以自动获取方法名称,而我们仅需要提供方法参数岂不是更好?在这种想法的指导下,我们再进一步改进:
public class HelloServiceProxy implements HelloService {
private HelloService service;
public HelloServiceProxy(HelloService service) {
this.service = service;
}
@Override
public void sayHello(String name) {
invoke(name);
}
public void after(Object target, Method method, Object[] params) {
System.out.println(">>>>>>after the method of " + method.getName());
}
public void before(Object target, Method method, Object[] params) {
System.out.println(">>>>>>before the method of " + method.getName());
}
private Object invoke(Object... params) {
Object result = null;
String methodName = MethodTool.getCallerMethodName(1);
try {
Class<?>[] types = new Class[params.length];
for (int i = 0; i < types.length; types[i] = params[i++].getClass())
;
Method m = service.getClass().getDeclaredMethod(methodName, types);
this.before(service,m, params);
result = m.invoke(service, params);
this.after(service,m, params);
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
}
到这里,我们基本上解决了有代码冗余的问题,这里有一个关键点,就是标红的代码段:
String methodName = MethodTool.getCallerMethodName(1);
这段代码的意思获取调用当前方法的方法名称,是我封装的类库中的方法,不同人可以有自己不同的实现.
上面的代码适用于多数代理的情况,因此我们可以抽象出来一个基类,并将before和after方法抽象成拦截器接口,于是上面的代码可以改造成如下:
/**
* 静态代理模式的抽象类<br>
* 该类不能独立使用,而是应当继承某个接口以后作为接口类型使用<br>
* 该类没有默认的构造方法,子类在实例化时需要显示调用该类的构造方法并提供构造参数<br>
* 由于父类的实例化先于子类,父类初始化时子类的实例成员尚未初始化,因此子类使用其实例成员变量作为父类的构造参数<br>
*
* @author skyfalling
*
*/
public abstract class AbstractProxy {
/**
* 被代理对象实例
*/
private Object target;
/**
* 拦截器实例
*/
private Interceptor interceptor;
/**
* 获取拦截器实例
*
* @return
*/
protected Interceptor getInterceptor() {
return interceptor;
}
/**
* 设置拦截器实例<br>
* 子类可以重置拦截器
*
* @param interceptor
*/
protected void setInterceptor(Interceptor interceptor) {
this.interceptor = interceptor;
}
/**
* 构造方法,传递被代理实例,参数由子类在实例化时提供<br>
* 这里需要注意的是,被代理的对象与该类的子类应该拥有相同的接口
*
* @param target
* 被代理对象实例
* @param interceptor
* 拦截器实例
*/
protected AbstractProxy(Object target) {
this(target, null);
}
/**
* 构造方法,传递被代理实例和拦截器,参数由子类在实例化时提供<br>
* 这里需要注意的是,被代理的对象与该类的子类应该拥有相同的接口
*
* @param target
* 被代理对象实例
* @param interceptor
* 拦截器实例
*/
protected AbstractProxy(Object target, Interceptor interceptor) {
this.target = target;
this.interceptor = interceptor;
}
/**
* 执行被代理对象中和调用者同名的方法<br>
* 调用该方法时,将会触发被代理对象的同名方法,并且在被代理对象方法执行过程中使用拦截器进行拦截处理
* 子类在接口实现中调用该方法,并传递参数,从而实现对代理对象的拦截处理<br>
*
* @param target
* @param params
* @return 返回代理结果
*/
protected Object proxy(Object... args) {
String methodName = MethodTool.getCallerMethodName(1);
Object result = null;
try {
Class<?>[] types = new Class[args.length];
for (int i = 0; i < types.length; types[i] = args[i++].getClass())
;
// 被代理的方法
Method method = this.target.getClass().getDeclaredMethod(
methodName, types);
// 代理前的处理
if (this.interceptor != null) {
this.interceptor.before(this.target, method, args);
}
try {
// 执行被代理的方法
result = method.invoke(this.target, args);
} catch (Exception ex) {
this.interceptor.doException(this.target, method, args, ex);
}
// 代理之后的处理
if (this.interceptor != null) {
this.interceptor.after(this.target, method, args);
}
} catch (Exception e) {
ExceptionHandler.throwException(e);
}
return result;
}
}
/**
* 拦截器的接口声明
*
* @author skyfalling
* 拦截对象的类型
*
*/
public interface Interceptor {
/**
* 拦截前处理
*
* @param target
* 被代理的实例
* @param method
* 被代理的方法
* @param args
* 被代理方法的参数
*/
void before(Object target, Method method, Object[] args);
/**
* 拦截后的处理
*
* @param target
* 被代理的实例
* @param method
* 被代理的方法
* @param args
* 被代理方法的参数
*/
void after(Object target, Method method, Object[] args);
/**
* 被拦截方法出现异常时的处理
*
*
* @param target
* 被代理的实例
* @param method
* 被代理的方法
* @param args
* 被代理方法的参数
* @param ex
* 异常实例
*/
void doException(Object target, Method method, Object[] args,Exception ex);
}
在进行了上述的抽象后,我们利用基类重新实现静态代理模式:
//静态代理类继承父类,实现接口方法
public class HelloServiceProxy extends AbstractProxy implements HelloService {
@Override
public void sayHello(String name) {
this.proxy(name);
}
public HelloServiceProxy(HelloService service) {
super(service,new ProxyInterceptor() {
@Override
public void after(Object target, Method method, Object[] params) {
System.out.println(">>>>>>after the method of " + method.getName());
}
@Override
public void before(Object target, Method method, Object[] params) {
System.out.println(">>>>>>before the method of " + method.getName());
}
});
}
//测试方法
static void test_static(){
HelloService service=new HelloServiceProxy(new HelloSerivceImpl());
service.sayHello("lining");
}
好了,我的关于静态代理模式的实现就是这样,以后实现代理的时候,只需继承静态代理的基类和代理对象的接口,对于接口中的方法实现中统一调用proxy方法即可.暂时能够优化的程度就到这了,如果进一步优化,恐怕需要动态改写字节码了,研究过javaassit的,可以考虑用它实现.
第一次发帖,如果哪里有错,欢迎批评指正,莫要拍砖!
分享到:
相关推荐
Java静态代理模式是一种设计模式,它允许我们为一个对象提供一个代理,以便增强或扩展其功能,同时不改变原有对象的代码。在Java中,静态代理是通过在代理类中显式实现目标接口来实现的。下面将详细介绍静态代理模式...
Java提供了两种实现代理的主要方式:静态代理和动态代理。 **静态代理** 静态代理是最基础的形式,它需要程序员手动创建一个代理类,该类实现了与目标类相同的接口。代理类持有目标类的引用,并在调用目标类方法...
下面我们将详细介绍静态代理的实现方式: 1. **定义接口**:首先,我们需要定义一个业务接口,这个接口会定义真实对象需要实现的方法,例如`Service`接口: ```java public interface Service { void ...
以下是一个简单的静态代理模式示例: 1. 定义接口: ```java public interface Service { void doSomething(); } ``` 2. 实现目标对象: ```java public class RealService implements Service { @Override ...
Java提供了两种实现代理模式的方式:静态代理和动态代理。 **静态代理** 静态代理是在编译时就已经确定了代理类,通过继承或实现目标接口来创建代理类。以下是一个简单的静态代理实现示例: ```java // 目标接口 ...
Java的代理模式通过代理类提供了对委托类的扩展和控制,静态代理适合对已有代码不做修改的情况,而动态代理则提供了更高的灵活性和扩展性。在实际应用中,应根据项目需求和性能考虑选择静态代理或动态代理。对于需要...
静态代理模式的核心思想是通过代理类来代理原始对象(也称为真实对象或服务对象),代理类通常与原始对象实现相同的接口,以便在客户端代码中可以透明地调用。代理类可以在调用真实对象的方法前后添加额外的操作,...
在Java中,静态代理的实现步骤如下: 1. **定义接口**:首先,我们需要定义一个公共接口,该接口描述了真实对象和代理对象需要共同实现的行为。 ```java public interface Service { void execute(); } ``` 2. **...
### Java 代理模式详解 #### 1. 代理模式概览 代理模式是一种设计模式,主要目的是为了控制或提供对某对象的访问。在代理模式中,代理对象充当客户端与真实对象之间的中介,使得客户端可以通过代理对象间接地访问...
下面是一个简单的静态代理模式示例: ```java public interface Service { void doSomething(); } public class RealService implements Service { @Override public void doSomething() { // 实现具体业务...
静态代理模式的核心思想是通过代理类作为真实对象的替代品,实现对真实对象的间接访问。代理类和真实对象通常会实现相同的接口,这样客户端可以通过代理对象调用方法,而代理对象则可以在调用真实对象的方法前后添加...
设计模式之代理模式_静态代理的一个java实现的demo。主类在Client中。仅代码实现,可供初学者参考使用
在Java中,代理模式有静态代理和动态代理两种实现方式。本篇将重点讨论"动态代理",这是一种在运行时创建代理对象的技术,使得我们可以在程序运行过程中,根据需要动态地生成具有额外功能的代理类。 动态代理主要由...
无论是通过代理模式控制对象的访问,还是利用Java动态代理实现特定时刻的行为增强,都是在不改变现有代码结构的前提下实现功能扩展的有效手段。这对于提高代码的可维护性和灵活性具有重要意义。
Java 动态代理详解(代理模式+静态代理+JDK动态代理+CGLIB动态代理) Java 动态代理是 Java 编程语言中的一种强大工具,广泛应用于 Spring AOP、Hibernate 数据查询、测试框架的后端 mock、RPC 远程调用、Java 注解...
在Java中,代理模式主要有静态代理和动态代理两种实现方式。 1. 静态代理:在编译时就已经确定了代理类与目标类的关系。通常,代理类会实现和目标类相同的接口,以便于在代理类中调用目标类的方法。这种方式的缺点...