使用JDK中的Proxy技术实现AOP功能

来学习下AOP技术,AOP技术在企业的开发中或多或少也被使用到,最主要的应用场合是在做权限的时候。都知道在做权限的时候我们要粗粒度的权限控制和碎粒度的权限控制,对于碎粒度的权限控制我们一般是对方法进行拦截,然后拦截到方法之后判断用户是否有权限,如果有权限就允许用户执行被拦截的方法,在我们的例子当中将模拟实际的业务需求,在不使用任何AOP框架的情况下,我们对业务bean里面的所有方法实现拦截,并且在拦截到方法后判断用户是否有调用方法的权限。。
现在就建一个AOP的项目,在这个项目里面不打算使用任何的AOP框架,我们看一下传统我们要实现AOP的话要怎么做。。

先提供一个需要被拦截的业务bean,先是接口
PersonService.java

package cn.itcast.service; 
 
public interface PersonService { 
    public void save(String name); 
    public void update(String name, Integer personid); 
    public String getPersonName(Integer personid); 
}



PersonServiceBean.java

package cn.itcast.service.impl; 
 
import cn.itcast.service.PersonService; 
 
public class PersonServiceBean implements PersonService{ 
    private String user = null;//提供一个用户,用String类型代表 
 
    public String getUser() { 
        return user; 
    } 
 
    public PersonServiceBean(){} 
 
    public PersonServiceBean(String user){ 
        this.user = user; 
    } 
 
    public String getPersonName(Integer personid) { 
        System.out.println("我是getPersonName()方法"); 
        return "xxx"; 
    } 
 
    public void save(String name) { 
        System.out.println("我是save()方法"); 
    } 
 
    public void update(String name, Integer personid) { 
        System.out.println("我是update()方法"); 
    } 
 
}


业务需求是这样的:要对PersonServiceBean这个业务bean里面的所有方法实施拦截,拦截到这个方法之后,我们判断用户是否为null,如果为null,就没有权限去调用里面的业务方法;如果用户不为null,则代表有权限去调用里面的方法。
现在我们要做的第一步是:
1.拦截所有业务方法
2.判断用户是否有权限,有权限就允许他执行业务方法,没有权限不允许他执行业务方法。(是否有权限是根据user是否为null作为判断依据)

如果让大家做,怎么做呢? 估计有些同学很快就想到一个非常简单的方法,比如下面这样写:

 
public String getPersonName(Integer personid) { 
    if(user != null){ 
        System.out.println("我是getPersonName()方法"); 
    } 
    return "xxx"; 
} 


看下这种实现好不好啊?肯定不行。因为这样的话,如果我们要控制更多业务bean里面的业务方法的话,那么我们的这些代码会出现在各个业务bean方法里面,这样这些代码就写死了,不灵活。如果你的权限判断依据一旦发生了改变之后呢,恐怕所有业务方法里面的判断方法都要做修改,显然这种方式是不行的。

还有其他方法吗? 有同学说用过滤器,这里能用过滤器吗?这里不是web应用,没办法用过滤器。
那么我们有没有更好的实现方案呢?以前学习的设计模式里面,曾经有一个代理,看一下我们使用代理技术的话,我们怎样实现拦截,并且在拦截到了之后呢做一下处理。

【客户端】 ---------> 【代理对象】 -----------> 【目标对象】
客服端在调用实际的目标对象之前呢(也就是说调用PersonServiceBean这个业务bean对象之前呢),它先经过代理对象,也就是说客户端调用的是代理对象,这个代理对象实现了目标对象的所有接口,所以通过代理对象的调用,他能把方法的调用委派给目标对象,更形象一下的话,大家可以想象在代理对象的方法内部,它调用了目标对象的方法,那么采用这种方案的话,我们不需要再在目标对象里面编写控制代码,而我们尽需要在代理对象里面对目标对象的方法在执行前做一个权限的判断就可以了。如果有权限,那么在代理对象里面我们才调用目标对象里面的方法。当然如果没有权限的话,就不调用目标对象里的方法。

现在怎么创建这个代理对象呢?代理对象的创建有两种实现方案,一种是静态代理,一种是动态代理,静态代理基本上在企业开发中很少用上,大部分是动态代理。动态代理就是说我们不需要再为目标对象去编写静态代理类了,我们只需要通过JDK或者第三方框架来动态生成代理对象的字节码就可以了。
那么以前在学习代理模式的时候,曾经学习到一个类,这个类是专门用于为目标对象动态创建代理对象,这个类是Proxy
现在就使用JDK提供的代理类来创建代理对象,想想在使用Proxy这个类的时候前提在于什么呢?它的应用前提是目标对象韩国阿朵cc霜必须要实现接口,也就是说目标对象必须面向接口的时候,
我们才能使用JDK提供的Proxy代理类来创建代理对象。如果目标对象它没有实现接口的话,Proxy类是不能使用的,它是有使用条件的。 现在学习下怎样通过代理类来创建代理对象。那么在创建代理对象之前呢,有必要说下前面的概念,前面提到了要拦截这些方法,拦截到方法后再对他们做处理,实际上我们所思考的这些步骤都属
于“横切性关注点”,也就是说对哪些方法实行拦截啊,然后拦截到后做什么工作啊,像这些思考的步骤我们都可以称为横切性关注点。 现在采用代理类Proxy创建代理对象 JDKProxyFactory.java
package cn.itcast.aop; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class JDKProxyFactory implements InvocationHandler { private Object targetObject; // 返回为目标对象创建好的代理对象 public Object createProxyIntance(Object targetObject) { this.targetObject = targetObject; // 第二个参数:代理对象要实现的接口是哪些? // 第三个参数:InvocationHandler,handler在C++是句柄的意思,在这,一般看到这个后缀实际上它是一个回调 // InvocationHandler这个类是一个接口,这里面的回调。。就是说拦截到方法的时候呢,可以触发哪个类里面的拦截方法 // 这里写this,就代表JDKProxyFactory这个类实例本身。。。这就要求这个类必须实现InvocationHandler接口 // 接口里面有个invoke方法 return Proxy.newProxyInstance(this.targetObject.getClass() .getClassLoader(), this.targetObject.getClass().getInterfaces(), this); } // 参数1:代理对象 // 参数2:被拦截到的方法 // 参数3:方法的输入参数 // 当我们对代理对象的业务方法进行调用的时候,这个调用操作会被上面的this拦截到,拦截到后会执行invoke方法 // 也就是说我们客户端调用代理对象的方法的时候,会调用this里面InvocationHandler这个接口决定的invoke方法 // 在invoke方法里面,如果我们要访问目标对象的话,我们就必须把代理对象方法的调用委派给目标对象, // 这里就要把方法的调用委派给method public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = method.invoke(targetObject, args); return result; } /* 在这里就实现了为目标类创建代理对象的代码,它的执行过程是这样的:当客户端调用代理对象的业务方法的时候,那么 代理对象就会执行invoke方法,在这方面里面,再把方法的调用委派给目标对象,也就相当于调用目标对象的method方法, 当然也要把方法的输入参数args输入进去 */ } 现在已经实现了方法的拦截,但是我们还没有判断用户是否有权限......能否执行业务方法.... JDKProxyFactory.java package cn.itcast.aop; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import cn.itcast.service.impl.PersonServiceBean; public class JDKProxyFactory implements InvocationHandler { private Object targetObject; // 返回为目标对象创建好的代理对象 public Object createProxyIntance(Object targetObject) { this.targetObject = targetObject; // 第二个参数:代理对象要实现的接口是哪些? // 第三个参数:InvocationHandler,handler在C++是句柄的意思,在这,一般看到这个后缀实际上它是一个回调 // InvocationHandler这个类是一个接口,这里面的回调。。就是说拦截到方法的时候呢,可以触发哪个类里面的拦截方法 // 这里写this,就代表JDKProxyFactory这个类实例本身。。。这就要求这个类必须实现InvocationHandler接口 // 接口里面有个invoke方法 return Proxy.newProxyInstance(this.targetObject.getClass() .getClassLoader(), this.targetObject.getClass().getInterfaces(), this); } // 参数1:代理对象 // 参数2:被拦截到的方法 // 参数3:方法的输入参数 // 当我们对代理对象的业务方法进行调用的时候,这个调用操作会被上面的this拦截到,拦截到后会执行invoke方法 // 也就是说我们客户端调用代理对象的方法的时候,会调用this里面InvocationHandler这个接口决定的invoke方法 // 在invoke方法里面,如果我们要访问目标对象的话,我们就必须把代理对象方法的调用委派给目标对象, // 这里就要把方法的调用委派给method public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { PersonServiceBean bean = (PersonServiceBean)this.targetObject; Object result = null; if(bean.getUser() != null){ result = method.invoke(targetObject, args); } return result; } /* 在这里就实现了为目标类创建代理对象的代码,它的执行过程是这样的:当客户端调用代理对象的业务方法的时候,那么 代理对象就会执行invoke方法,在这方面里面,再把方法的调用委派给目标对象,也就相当于调用目标对象的method方法, 当然也要把方法的输入参数args输入进去 */ } 我们通过JDKProxyFactory这个工厂类可以创建代理对象,为目标对象创建代理类。当代理对象的方法执行的时候,它会回调这个方法,也就是说invoke这个方法会被调用,在invoke方法里面,首先取得用户名,如果用户名不为null,就代表有权限,我们就让它执行目标对象的业务方法,没权限的话就不让它执行。 现在就在客户端执行下我们的应用,看下当我们不使用任何AOP框架的时候,我们是否也能实现AOP功能,建个单元测试 AOPTest.java package junit.test; import org.junit.BeforeClass; import org.junit.Test; import cn.itcast.aop.JDKProxyFactory; import cn.itcast.service.PersonService; import cn.itcast.service.impl.PersonServiceBean; public class AOPTest { @BeforeClass public static void setUpBeforeClass() throws Exception { } @Test public void proxyTest() { JDKProxyFactory factory = new JDKProxyFactory(); PersonService service = (PersonService) factory.createProxyIntance(new PersonServiceBean("xxx")); /*注意:这个代理对象,我们应该采用接口来引用它,采用return Proxy.newProxyInstance(this.targetObject .getClass().getClassLoader(),this.targetObject.getClass().getInterfaces(), this); 这里面出现的接口引用这个代理对象,因为代理对象是实现了这个接口的 */ service.save("888"); //调用这个方法,invoke就会被调用 } } 运行单元测试,控制台输出:我是save()方法 加入上面代码改动一句如下:PersonService service = (PersonService) factory.createProxyIntance(new PersonServiceBean("")); 运行单元测试代码,没用任何东西输出 可以看到,我们采用动态代理创建技术就可以实现业务需求

 

http://www.java63.com/spring/use_jdk_proxy_implement_aop.html

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 以下是 JDK 动态代理实现 AOP 的步骤: 1. 创建一个接口,定义需要进行 AOP 的方法。 2. 创建一个代理类,实现 InvocationHandler 接口,并重写 invoke 方法。 3. 在 invoke 方法,根据需要进行 AOP 增强处理,例如在方法前后添加日志、事务等等。 4. 使用 Proxy 类的 newProxyInstance 方法创建代理对象。 5. 将代理对象转换为接口类型,并调用接口方法,代理类的 invoke 方法会被调用,从而实现 AOP 增强处理。 下面是一个简单的例子,演示如何使用 JDK 动态代理实现 AOP: ```java // 定义接口 public interface UserService { void addUser(String name); } // 实现接口 public class UserServiceImpl implements UserService { public void addUser(String name) { System.out.println("添加用户:" + name); } } // 代理类 public class UserServiceProxy implements InvocationHandler { private Object target; public UserServiceProxy(Object target) { this.target = target; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("开始事务"); Object result = method.invoke(target, args); System.out.println("提交事务"); return result; } } // 使用代理类 public class Main { public static void main(String[] args) { UserService userService = new UserServiceImpl(); UserService proxy = (UserService) Proxy.newProxyInstance(userService.getClass().getClassLoader(), userService.getClass().getInterfaces(), new UserServiceProxy(userService)); proxy.addUser("张三"); } } ``` 运行结果: ``` 开始事务 添加用户:张三 提交事务 ``` ### 回答2: JDK动态代理是一种实现AOP(面向切面编程)的方式。AOP主要是通过在程序运行期间动态地将额外的逻辑注入到目标对象的方法,从而实现横切关注点的分离和复用。JDK动态代理是Java语言提供的一种代理方式,基于接口实现动态代理,以下是其实现AOP的步骤: 1. 定义切面类:切面是横切关注点的实现,一般包括需解决的问题和实现逻辑。切面类通常实现了InvocationHandler接口。 2. 创建目标对象:创建需要被代理的目标对象,并且实现了接口。 3. 获取代理对象:通过Proxy的newProxyInstance()方法获取代理对象。该方法接收三个参数,分别是目标对象的ClassLoader、目标对象的所有接口以及切面对象。 4. 调用代理对象方法:通过代理对象调用方法时,会自动触发InvocationHandler的invoke()方法。 5. 在invoke()方法实现逻辑:在invoke()方法,我们可以根据需要进行一些额外的逻辑操作,如在目标方法之前或之后进行一些其他操作。 通过以上步骤,JDK动态代理可以在运行时为目标对象的方法添加额外的逻辑实现,达到AOP的目的。这种方式的优点是实现简单,无需引入额外的依赖库,且支持接口代理;但缺点是只能通过接口进行代理,无法对类进行直接代理。 ### 回答3: JDK动态代理是一种实现面向切面编程(AOP)的方式之一。以下是JDK动态代理实现AOP的步骤: 1. 定义切面类:首先,我们需要定义一个切面类,该类包含了我们要在目标对象的方法之前或之后执行的代码。切面类需要实现InvocationHandler接口。 2. 创建目标对象:接下来,我们需要创建一个目标对象,即我们要在其方法上实施切面的对象。 3. 创建代理对象:使用Proxy类的静态newProxyInstance方法创建一个代理对象。该方法接受三个参数:ClassLoader对象、目标对象的接口数组以及InvocationHandler对象。ClassLoader负责加载代理对象,目标对象的接口数组指定了代理对象需要实现的接口,InvocationHandler对象执行切面逻辑。 4. 调用方法:通过代理对象调用目标对象的方法,代理对象会在方法执行前后执行切面逻辑。 5. 前置通知:在切面类的invoke方法,我们可以通过method.invoke(target, args)调用目标对象的方法,同时可以在此之前执行我们定义的前置通知。 6. 后置通知:在切面类的invoke方法,我们同样可以通过method.invoke(target, args)调用目标对象的方法,同时可以在此之后执行我们定义的后置通知。 总结:JDK动态代理实现AOP的步骤包括定义切面类、创建目标对象、创建代理对象,调用方法以及前置和后置通知的执行。使用代理对象调用目标对象的方法时,会自动执行所定义的切面逻辑,从而实现AOP的效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值