第六章 JDK代理模式
Spring中的AOP技术实际上就是Struts2中的拦截器,只不过针对的对象不同,
Spring中的AOP技术: 拦截业务层的方法
Struts2中的拦截器: 拦截Action中的请求
我们先来模拟一个业务需求
UserService:
public interface UserService {
public void create();
public void update();
public void delete();
}
UserServiceImpl:
public class UserServiceImpl implements UserService {
private String user;
public UserServiceImpl() {
super();
}
public UserServiceImpl(String user) {
super();
this.user = user;
}
@Override
public void create() {
System.out.println("create方法执行");
}
@Override
public void delete() {
System.out.println("delete方法执行");
}
@Override
public void update() {
System.out.println("update方法执行");
}
}
可以看到服务层实现类中有一个持有User对象,我们现在的要求是如果用户为null,则没有权限调用create,update,delete这些方法,如果不为空则可以调用.
最原始的方法,我们可以这样做:
private String user;
public UserServiceImpl() {
super();
}
public UserServiceImpl(String user) {
super();
this.user = user;
}
@Override
public void create() {
if(user != null){
System.out.println("create方法执行");
}
}
@Override
public void delete() {
if(user != null){
System.out.println("delete方法执行");
}
}
@Override
public void update() {
if(user != null){
System.out.println("update方法执行");
}
}
}
这叫硬编码,灵活性差,如果一但权限需求发生改变,一动则全身都得动,如果非常庞大的系统,有几百个业务层的类,都需要进行权限拦截,那不是每个方法都得加上判断语句,可以想像一下,如果日后需求发生变更,修改程序是多么恐怖的一件事情.这个时候我们肯定得想办法将这些相同的代码(这里是判断语句)抽取出来.
下面我们先来看一下JDK中(不使用任何框架)对AOP的一个支持.
那这个时候我们需要先来了解一下代理模式,代理模式有点像经纪人的味道.
比如: 企业找明星代言产品.
企业 ? 经纪人 ? 明星
这个时候,可以看到企业首先并不是直接和明星沟通合作事宜的, 而是先通过明星的经纪人来洽谈一些大概的合作事项,如果有意向,才能再与明星直接进行沟通合作事宜.
经纪人在这里充当的角色就是代理对象,那么我们怎么来生成这个经纪人代理对象呢,请看下面:
在Java中, JDK已经内置实现这种模式的一种机制—代理.
( java.lang.reflect.Proxy)类:
Proxy 提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类。
动态代理类(以下简称为代理类)是一个实现在创建类时在运行时指定的接口列表的类,该类具有下面描述的行为。
代理接口:是代理类实现的一个接口。 InvocationHandler
代理实例:是代理类的一个实例。 实现了InvocationHandler接口的类
每个代理实例都有一个关联的调用处理程序 对象,它可以实现接口 InvocationHandler。通过其中一个代理接口的代理实例上的方法调用将被指派到实例的调用处理程序的 Invoke 方法,并传递代理实例、识别调用方法的 java.lang.reflect.Method 对象以及包含参数的 Object 类型的数组。调用处理程序以适当的方式处理编码的方法调用,并且它返回的结果将作为代理实例上方法调用的结果返回。
使用JDK的AOP进行拦截方法, API上面说的非常清楚,代理对象必须实现一个接口
public interface InvocationHandler
InvocationHandler 是代理实例的调用处理程序 实现的接口。 此接口中提供一个方法Invoke,
Invoke方法简单理解:
当你获取到了代理对象(代理对象和原始对象一样,实现了共同的接口)以后,在代理对象上调用接口中暴露的方法,这个时候就会先调用Invoke方法,然后再调用原始类中的实际方法.
在Invoke方法中,此时我们就可以做拦截处理了
JDKProxyFactory:
public class JDKProxyFactory implements InvocationHandler {
private Object targetObj;
public Object getInstance(Object targetObj) {
this.targetObj = targetObj;
return Proxy.newProxyInstance(targetObj.getClass().getClassLoader(),
targetObj.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
UserServiceImpl userServiceImpl = (UserServiceImpl)targetObj;
if(userServiceImpl.getUser() != null){
return method.invoke(targetObj, args);
}
return null;
}
}
Test:
public class Test {
public static void main(String[] args) {
JDKProxyFactory factory = new JDKProxyFactory();
UserService userService = (UserService)factory.getProxyInstance(new UserServiceImpl("zhd"));
userService.create();
}
}
代理模式图:
接收返回的代理对象,应该使用service 接口来接收.