用java实现AOP主要用到了java反射机制,java动态代理,java注释。分别对应java.lang.reflect;java.lang.annotation包。关于自定义注释这里不再讲,请看代码:
定义Aop注释
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Aop
{
String className();
String methodName();
String methodArgs() default "";
String argTypes() default "";
AopPolicy policy() ;
}
定义Aop切入的方法
public enum AopPolicy
{
Begin,End
}
下面是Aop功能的实现,在这里,我想说下java的动态代理功能,好多人对java动态代理的机制理解不深,小编也曾经困惑过:
java动态代理机制说白了就是两个主要的方法,一个是Proxy类的static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)方法,这是一个静态方法,返回代理类实例。
还有一个就是InvocationHandler类的 Object invoke(Object proxy, Method method, Object[] args) 方法,这个方法是调用处理程序。
来看我们的Aop实现类:
import java.lang.reflect.*;
import java.util.*;
public class AopConsole implements InvocationHandler
{
public Object obj;//代理的实际对象
public AopConsole(){}
public AopConsole(Object obj)
{
this.obj=obj;
}
public static Object bind(Class[] interfaces,Object obj)
{
return Proxy.newProxyInstance(interfaces[0].getClassLoader(),interfaces,new AopConsole(obj));
}
public static Object bind(Class a,Object obj)
{
return bind(new Class[]{a},obj);
}
/**
*proxy为代理类的一个实例
*method为代理的那个方法,这个方法使用的地址是接口中的那个方法的地址,一定要注意
*args为代理的那个方法的参数
*/
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable
{
Object result=null;
Object obegin=null,oend=null;
Method mbegin=null,mend=null;
/************以下部分为 获取被代理的方法的AOP注释的内容**************/
Aop aop = method.getAnnotation(Aop.class);//得到这个方法的注释,这个注释一定是在接口中的注释,因为这是java的反射机制是基于接口的
String aopClassName = aop.className();
String aopMethodName=aop.methodName();
String methodArgs=aop.methodArgs();
String argTypes=aop.argTypes();
AopPolicy aopPolicy=aop.policy();
/************以上部分为 获取被代理的方法的AOP注释的内容**************/
/************以下部分为找出在AOP中药切入的方法调用 ,也就是对obegin,oend,mbegin,mend赋值 **/
Class aopClass=Class.forName(aopClassName);
Method[] methods = aopClass.getMethods();
boolean flag=false;
for(int i=0;i<methods.length;i++)
{
//对于AOP要调用的方法
if((methods[i].getName().equals(aopMethodName))&&(getMethodParamTypes(methods[i]).equals(argTypes)))
{
if(aopPolicy==AopPolicy.Begin)
{
obegin=aopClass.newInstance();
mbegin=methods[i];
}
else if (aopPolicy==AopPolicy.End)
{
oend=aopClass.newInstance();
mend=methods[i];
}
flag=true;
}
}
if(flag==false)
{
System.out.println("找不到AOP注释中要切入的方法");
}
/*****以上部分为找出在AOP中药切入的方法调用 ,也就是对obegin,oend,mbegin,mend赋值*********/
/****以下部分为进行AOP增强处理*********/
if(obegin!=null)
{
mbegin.invoke(obegin,getMethodArgs(methodArgs));//AOP附加的方法
}
result=method.invoke(obj,args);//注意,此处为proxy(代理类对象),而非obj(代理实例对象)
if(oend!=null)
{
mend.invoke(oend,getMethodArgs(methodArgs));//AOP附加的方法
}
return result;//此处返回原方法的调用结果,正好符合了aop编程的实际情况
/****以上部分为进行AOP增强处理********/
}
/**
*以String形式返回method方法的参数类型
*没有参数时候,返回""
*有参数时,例如返回int,java.lang.String,java.lang.String
*/
private static String getMethodParamTypes(Method method)
{
//返回参数类型,用String表示
Class [] paramTypes=method.getParameterTypes();
String paramTypes_str="";
if(paramTypes.length!=0)
{
StringBuffer sb=new StringBuffer("");
for(int j=0;j<paramTypes.length;j++)
{
sb.append(paramTypes[j].getName()+",");
}
paramTypes_str=sb.substring(0,sb.length()-1);
}
return paramTypes_str;
}
/**
*将String类型的methodArgs转换为Obj[]
*/
private static Object[] getMethodArgs(String methodArgs)
{
Object [] aopArgs=null;
if(!("".equals(methodArgs)))
{
aopArgs=methodArgs.split(",");
}
return aopArgs;
}
}
这是要实现Aop的接口:
public interface Sell
{
//@Aop(className="Present",methodName="give",methodArgs="",policy=AopPolicy.Begin)
//@Aop(className="Present",methodName="give",methodArgs="liming",argTypes="java.lang.String",policy=AopPolicy.End)
@Aop(className="Present",methodName="give",methodArgs="present,liming",argTypes="java.lang.String,java.lang.String",policy=AopPolicy.End)
public void sell();
}
public class Factory implements Sell
{
public void sell()
{
System.out.println("卖产品");
}
}
下面是Aop要植入的方法所在的类:
public class Present
{
public void give(String sth,String name)
{
System.out.println("送"+sth+" 给 "+name);
}
public void give(String name)
{
System.out.println("送礼品给 "+name);
}
public void give()
{
System.out.println("送礼品");
}
}
下面是测试类:
public class Test
{
public static void main(String [] args)
{
Sell s=(Sell)AopConsole.bind(Sell.class,new Factory());
s.sell();
}
}
以上面的例子为例,我们继续来说java动态代理,本来在Test中,我们可以使用new Factory().sell()来买东西,但一段时间之后,发现光买东西不行,得赠送礼品顾客才能买我的产品,这就是Aop要解决的问题,这个时候怎么办呢?
当然你可以修改Factory类,但是软件的OCP原则不允许我们这么做,因此,我们要使用Aop编程。
首先在Test类中,我们建立了new Factory()这个对象的代理对象s,由bind的两个参数可知,代理对象实例s要代理new Factory()对象,并且仅仅代理Sell接口中的那些方法,在看看sell接口中的方法,于是,我们可以理解,其实在代理实例s中存储了他要代理的对象new Factory()的InvocationHandler对象new AopConsole(new Factory())以及要代理的方法sell(),
要注意这个sell方法是代理实例s从Sell接口中了解到的,好了至此,我们知道了代理对象里面都是什么内容。
接着Test中的第二句s.sell();语句,java动态代理机制在执行这个语句时就起作用了,首先他会查看s能代理sell吗?已查看实现的接口,发现能代理sell,这个时候,执行new AopConsole(new Factory()).invoke(Object proxy,Method method,Object[] args) throws Throwable
;也就是说执行InvocationHandler类的invoke方法,此时,new Factory()就是我们在Test只能怪传入的那个Factory对象,method就是sell方法,参数就是Test中sell方法的参数,这里为null,而proxy自然是代理类对象s,自此,
因此可以知道在InvocationHandler类的invoke中,使用method.invoke(obj,args);而不是用method.invoke(proxy,args)至于代理的时候,还要增加什么操作,就自己说的算了,反正被代理方法的只用由method.invoke(obj,args)就可以完成。
这个例子中,笔者尝试的写了一个类似Spring中实现通过注释实现AOP的功能,由于仅仅是为了研究动态代理,所以仅仅支持方法参数是String类型的,其他类型,读者可以自行扩展。
另外,容易犯错的是,实现AOP的时候,实现AOP的注释一定要在接口中声明,在本例子中,就是Sell接口中,在Factory中注释是无效的,运行报错,至于其中缘由,已经在文章中的红体字说明,不再赘述。