java.lang.reflect.Proxy 、java.lang.reflect.InvocationHandler
不知道怎么去解释了,如果使用Proxy 获取一个类的实例,那么在调用这个类的方法前会先执行InvocationHandler 的invoke方法,那么我们就可以利用这个特性来实现自己的AOP了,下面的例子将介绍如何实现Spring 中AOP的前通知、后通知和环绕通知。实现思路如下:
1.DynaProxy动态代理类实现接口InvocationHandler,getBean方法 返回要代理的类,(这个类必须是基于接口的),invoke方法被代理的类执行其方法前一定要调用的方法,在这个方法里面可以在控制被调用的方法是否执行,或者做点其他事情。写日志,性能计算,权限控制等,setMethodAdvice方法,绑定自己定义的通知类。
2.MethodAdvice,加载自己定义的消息通知。目前支持前通知,后通知,和环绕通知,要实现这个三个功能只需要实现对应的接口,(^_^这些接口也是我自己定义的),然后通用方法AddAdvice加载进去,这里支持多个消息通知,对于多个消息通知执行的顺序是环绕通知,前通知,后通知。
3.定义了四个接口Advice、AroundAdvice、BeforeAdvice、AfterAdvice
4.实现3个Advice的实现类,分别对应环绕通知,前通知,后通知。
5.实现自己的消息通知类MyAdvice
6.编写测试类Test
下面看具体的代码实现
-
-
packagecom.advice;
-
importjava.lang.reflect.InvocationHandler;
-
importjava.lang.reflect.Method;
-
importjava.lang.reflect.Proxy;
-
-
-
publicclassDynaProxyimplementsInvocationHandler{
-
privateMethodAdvicemethodAdvice;
-
privateObjectdelegate;
-
@Override
-
publicObjectinvoke(Objectporxy,Methodmethod,Object[]args)
-
throwsThrowable{
- methodAdvice.setArgs(args);
- methodAdvice.setMethod(method);
-
methodAdvice.setProxy(this);
-
methodAdvice.setPos(-1);
-
methodAdvice.setDone(false);
-
returnmethodAdvice.proceed();
- }
-
publicObjectgetBean(StringclassName){
-
try{
- delegate=Class.forName(className).newInstance();
- methodAdvice.setTarget(delegate);
-
returnProxy.newProxyInstance(
- delegate.getClass().getClassLoader(),
-
delegate.getClass().getInterfaces(),this);
-
}catch(Exceptione){
- e.printStackTrace();
- }
-
returnnull;
- }
-
publicMethodAdvicegetMethodAdvice(){
-
returnmethodAdvice;
- }
-
publicvoidsetMethodAdvice(MethodAdvicemethodAdvice){
-
this.methodAdvice=methodAdvice;
- }
- }
-
packagecom.advice;
-
publicinterfaceAdvice{
-
publicObjectinvoke(MethodAdvicemethodAdvice);
- }
-
packagecom.advice;
-
publicinterfaceAroundAdviceextendsAdvice{
- }
-
packagecom.advice;
-
importjava.lang.reflect.Method;
-
publicinterfaceBeforeAdvice{
-
publicvoidbefore(Methodm,Object[]args,Objecttarget);
- }
-
packagecom.advice;
-
importjava.lang.reflect.Method;
-
publicinterfaceAfterAdvice{
-
publicvoidafter(Methodm,Object[]args,Objecttarget);
- }
-
packagecom.advice.impl;
-
importcom.advice.Advice;
-
importcom.advice.MethodAdvice;
-
publicclassAroundAdviceImplimplementsAdvice{
-
privateAdviceadvice;
-
@SuppressWarnings("unused")
-
privateAroundAdviceImpl(){};
-
publicAroundAdviceImpl(Adviceadvice){
-
this.advice=advice;
- }
-
@Override
-
publicObjectinvoke(MethodAdvicemethodAdvice){
-
returnadvice.invoke(methodAdvice);
- }
- }
-
packagecom.advice.impl;
-
importcom.advice.Advice;
-
importcom.advice.BeforeAdvice;
-
importcom.advice.MethodAdvice;
-
publicclassBeforeAdviceImplimplementsAdvice{
-
privateBeforeAdvicebeforeAdvice;
-
@SuppressWarnings("unused")
-
privateBeforeAdviceImpl(){
- }
-
publicBeforeAdviceImpl(BeforeAdvicebeforeAdvice){
-
this.beforeAdvice=beforeAdvice;
- }
-
@Override
-
publicObjectinvoke(MethodAdvicemethodAdvice){
- beforeAdvice.before(methodAdvice.getMethod(),methodAdvice.getArgs(),methodAdvice.getTarget());
-
returnmethodAdvice.proceed();
- }
- }
-
packagecom.advice.impl;
-
importcom.advice.Advice;
-
importcom.advice.AfterAdvice;
-
importcom.advice.MethodAdvice;
-
publicclassAfterAdviceImplimplementsAdvice{
-
privateAfterAdviceafterAdvice;
-
@SuppressWarnings("unused")
-
privateAfterAdviceImpl(){}
-
publicAfterAdviceImpl(AfterAdviceafterAdvice){
-
this.afterAdvice=afterAdvice;
- }
-
@Override
-
publicObjectinvoke(MethodAdvicemethodAdvice){
- ObjectretVal=methodAdvice.proceed();
- afterAdvice.after(methodAdvice.getMethod(),methodAdvice.getArgs(),methodAdvice.getTarget());
-
returnretVal;
- }
- }
-
packagecom.myadvice.test;
-
importjava.lang.reflect.Method;
-
importjava.util.Arrays;
-
importbsh.EvalError;
-
importbsh.Interpreter;
-
importcom.advice.AfterAdvice;
-
importcom.advice.AroundAdvice;
-
importcom.advice.BeforeAdvice;
-
importcom.advice.MethodAdvice;
-
publicclassMyAdviceimplementsBeforeAdvice,AfterAdvice,AroundAdvice{
-
-
-
@Override
-
publicvoidafter(Methodm,Object[]args,Objecttarget){
-
System.out.println("后通知,调用的方法:"+m.getName()+",参数:"+Arrays.toString(args));
- }
-
-
-
@Override
-
publicObjectinvoke(MethodAdvicemethodAdvice){
-
System.out.println("[环绕通知]");
-
-
-
if(methodAdvice.getMethod().getName().equals("comment")"李四".equals(methodAdvice.getArgs()[0])){
-
System.out.println("屏蔽李四所有的评论");
- StringreturnType=methodAdvice.getMethod().getReturnType().getName();
-
if("int".equals(returnType)||"long".equals(returnType)||"float".equals(returnType)||"double".equals(returnType)||"byte".equals(returnType)||"short".equals(returnType)){
-
-
-
Interpreteri=newInterpreter();
-
try{
-
returni.eval("("+returnType+")0");
-
}catch(EvalErrore){
-
- e.printStackTrace();
- }
-
}elseif("boolean".equals(returnType)){
-
returnfalse;
- }
-
returnnull;
-
}else{
-
returnmethodAdvice.proceed();
- }
- }
-
-
-
@Override
-
publicvoidbefore(Methodm,Object[]args,Objecttarget){
-
System.out.println("前通知,调用的方法:"+m.getName()+",参数:"+Arrays.toString(args));
- }
- }
-
packagecom.myadvice.test;
-
importcom.advice.DynaProxy;
-
importcom.advice.MethodAdvice;
-
importcom.test.BookBiz;
-
importcom.test.BookBizImpl;
-
publicclassTest{
-
-
-
publicstaticvoidmain(String[]args){
-
DynaProxyproxy=newDynaProxy();
-
MethodAdvicemethodAdvice=newMethodAdvice();
-
methodAdvice.AddAdvice(newObject[]{newMyAdvice()});
- proxy.setMethodAdvice(methodAdvice);
-
BookBizbookBiz=(BookBiz)proxy.getBean(BookBizImpl.class.getName());
-
bookBiz.buy("张三","Spring深入潜出",50);
-
bookBiz.comment("李四","《恐怖世界》一点都不恐怖,很好看!");
-
bookBiz.comment("张三","《Spring深入潜出》还是写得不错的!");
- }
- }
运行Test类得到下面的结果:
[环绕通知]
前通知,调用的方法:buy,参数:[张三, Spring深入潜出, 50.0]
业务方法buy开始执行
·张三购买图书:Spring深入潜出
·张三增加积分:5
·向物流系统下发货单
业务方法buy结束
后通知,调用的方法:buy,参数:[张三, Spring深入潜出, 50.0]
[环绕通知]
屏蔽李四所有的评论
[环绕通知]
前通知,调用的方法:comment,参数:[张三, 《Spring深入潜出》还是写得不错的!]
业务方法comment开始执行
·张三发表书评《Spring深入潜出》还是写得不错的!
业务方法comment结束
后通知,调用的方法:comment,参数:[张三, 《Spring深入潜出》还是写得不错的!]
从结果可以看出和使用spring的一样。
这个又个小小的问题,为什么spring里面前通知后通知的接口方法要包含Object object, Method method这两个参数,如果又这里两个参数那么就可以在前后通知里面去执行目标方法了,这样不是很好。还有就是使用jdk的代理,被代理的类都必须是基于接口的,重要也不是很方便,如果使用cglib动态代理类,那么被代理的类就可以不是基于接口的了,这样比较方便,下一篇将介绍如何使用cglib动态代理
分享到:
相关推荐
**Spring AOP 示例讲解** Spring AOP(Aspect Oriented Programming,面向切面编程)是Spring框架中的一个重要模块,它提供了一种在不修改源代码的情况下,对程序进行功能增强的技术。这种技术允许开发者将关注点从...
在这个“Spring AOP 1.0示例”中,我们重点关注如何在实际项目中应用这一特性。 首先,我们需要了解AOP的基本概念。AOP的核心思想是将那些影响多个类的公共行为(如日志记录)抽取出来,形成独立的模块,称为切面...
在"基于realproxy的aop使用示例"中,我们可能看到以下步骤: 1. **创建代理类**:首先,我们需要创建一个继承自RealProxy的子类,这个子类负责拦截目标对象的方法调用。在这个子类中,我们可以重写`Invoke`方法,该...
本示例将深入探讨Spring AOP的基础知识,以及如何在实际应用中使用它。 首先,我们来看"LogProfilter.java",这很可能是实现一个日志拦截器的类。在Spring AOP中,这样的类通常被称为切面(Aspect)。切面是封装了...
Spring AOP,全称Aspect-Oriented Programming(面向切面编程),是Spring框架的一个重要组成部分。它提供了一种模块化和声明式的方式来处理系统中的交叉关注点,如日志、性能监控、安全性、事务管理等。通过AOP,...
纯手工打造Emit实现AOP private static void OverrideMethods(TypeBuilder tb, MethodInfo method) { if (!method.IsPublic|| !method.IsVirtual || IsObjectMethod(method)) return; Type[] paramTypes = ...
在这个"Spring AOP简单示例"中,我们将深入探讨这五个关键元素,并通过XML配置来实现它们。 首先,**切面(Aspect)**是关注点的模块化,这些关注点定义了跨越多个对象的行为或责任。在Spring AOP中,切面可以是...
这个“Spring AOP示例”包含了一个具体的实践案例,帮助我们更好地理解和应用Spring AOP。 在Spring AOP中,核心概念有以下几个: 1. **切面(Aspect)**:切面是关注点的模块化,比如事务管理就是一个切面。在...
本示例DEMO "Spring的AOP示例DEMO HELLOWORLD" 将引导我们深入理解Spring AOP的核心概念,并通过一个简单的 HelloWorld 示例来展示其实现过程。 首先,面向切面编程(AOP)是一种编程范式,旨在提高代码的可维护性...
在这个"spring aop API示例"中,我们将深入探讨如何利用Spring AOP的四种通知类型:Before、After、AfterThrowing和Around,以及它们在实际开发中的应用。 1. **Before通知**: 在方法执行前触发,可以用来执行...
在本示例中,我们将深入探讨Spring框架2.5.6版本中的面向切面编程(AOP)概念。Spring AOP是Spring框架的核心组件之一,它允许开发者在不修改源代码的情况下,对程序进行横切关注点(如日志、事务管理、性能监控等)...
本示例将详细阐述如何通过XML配置来实现Spring AOP。 首先,我们需要理解AOP的基本概念。AOP的核心是切面(Aspect),它封装了横切关注点,也就是那些跨越多个对象的业务逻辑。这些关注点通常包括日志、安全检查和...
SpringAOP Spring AOP(面向方面的编程)用于模块化“横截面”服务。 用一种简单的方式,我们可以说它是一个旨在拦截某些进程的组件,例如,在执行某个方法时,Spring AOP可以... 以下示例将向您展示其工作原理
Spring框架的AOP(面向切面编程)正是为了解决这类问题而设计的。AOP允许我们在不修改原有业务逻辑的情况下,将这些共性功能以一种模块化的方式插入到业务代码中,从而提高了代码的可复用性和可维护性。 首先,理解...
Spring IOC AOP学习示例代码,包含Spring常用操作示例和所有所需jar文件。参考博客:http://blog.csdn.net/daijin888888/article/details/51735291
在本教程的示例中,你可能发现了一些配置文件,如`applicationContext.xml`,它们用于装配切面。在Spring XML配置中,我们可以使用`<aop:config>`元素来定义切点表达式,然后使用`<aop:aspect>`元素来声明切面,并将...
在这个"spring aop示例"中,我们看到了如何使用Spring AOP来实现方法执行前打印方法名和参数的功能。这主要涉及到三个方面:AOP的基本概念、注解的使用以及Spring的自动注入。 首先,AOP的核心概念包括切面(Aspect...
以下是一个简单的Spring AOP示例,展示如何使用注解定义切面和通知: ```java // 定义切面 @Aspect @Component public class LoggingAspect { // 定义切入点,匹配所有以'execute'开头的方法 @Pointcut(...
而压缩包子文件的文件名称列表"SSHibernate"可能是表示这是一个关于Spring、Struts和Hibernate整合的示例项目,特别强调了Hibernate的部分。Hibernate是Java领域的一个持久化框架,用于简化数据库操作。在SSH整合...
AOP(Aspect-Oriented Programming)这个东西,名字与 OOP 仅差一个字母,其实它是对 OOP 编程方式的一种补充,并非是取而代之。翻译过来就是“面向方面编程”,可我更倾向于翻译为“面向切面编程”。最好的演示案例...