`
臻是二哥
  • 浏览: 183886 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
博客专栏
Group-logo
Java技术分享
浏览量:0
社区版块
存档分类
最新评论

java实现简单AOP

    博客分类:
  • JAVA
阅读更多
用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中注释是无效的,运行报错,至于其中缘由,已经在文章中的红体字说明,不再赘述。
0
0
分享到:
评论

相关推荐

    Java利用spring aop进行监测方法执行耗时

    代码实现简单,易于维护:使用 Spring AOP 可以将耗时监测的逻辑与业务逻辑进行解耦,避免业务逻辑代码的冗余和代码维护难度的提高。 2. 安全性高:使用 Spring AOP 进行方法耗时监测,可以在不修改业务逻辑代码的...

    java 实现AOP

     为了简单起见,例子没有没有使用任何第三方的AOP Framework, 而是利用Java语言本身自带的动态代理功能来实现AOP.  让我们先回到AOP本身,AOP主要应用于日志记录,性能统计,安全控制,事务处理等方面。它的主要...

    java实现日志aop切面 和业务功能进行解耦

    1.只需要在controller层增加自定义@RequestLog注解就可以实现了。 @RequestLog功能参数如下: 功能一:是否记录请求参数 功能二:是否记录请求日志 功能三:是否记录返回值 功能四:是否以debug形式记录 功能五:日志类型 ...

    用Java动态代理实现AOP

    Java初学者不禁要发出感慨,OOP还没有学通呢,又来AOP。本文不是要在理论上具体阐述何为AOP, 为何要进行AOP . 要详细了解学习AOP可以到它老家http://aosd.net去瞧瞧。这里只是意图通过一个简单的例子向初学者展示...

    注解+AOP优雅的实现java项目的接口参数校验(含源码)

    基于Spring boot + maven,以注解+AOP方式实现的java后端项目接口参数校验框架。迄今为止使用最简单、最容易理解的参数校验方案。博客地址:https://blog.csdn.net/weixin_42686388/article/details/104009771

    java分页 动态代理 aop实现

    动态代理 实现简单分页 spring aop 实现简单分页

    Java动态代理在AOP中的应用

    本文首先介绍了AOP 的基本思想,然后针对它在JAVA 语言 中的实现,具体介绍了JAVA 的动态代理来怎样实现一个简单的AOP 容器

    手写简单实现ioc、aop事务demo

    手写简单实现ioc、aop事务demo,实现事务回滚,使用到了,工厂模式,动态代理

    基于Java仿Spring实现简单的 IoC 和 AOP【100012181】

    本项目包含了两个不同版本的 IoC 和 AOP 实现,相关源码包结构如下: simple,包含了简单的 IoC 和 AOP 实现代码 IoC,包含了较为复杂的 IoC 实现代码 aop,包含了较为复杂的 AOP 实现代码

    使用java动态代理技术实现简单的AOP切面编程实例

    对应的博客链接:http://blog.csdn.net/JQ_AK47/article/details/60469034#t12

    Java_AOP.zip_AOP ja

    java aop 详细介绍 Java通过一个类Proxy以及一个接口InvocationHandler来实现函数接管的功能,这两个类都是在java.lang.reflect包中。 对接管对象如本例中的TestProxy的要求: 必须实现接口InvocationHandler。 ...

    如何实现Spring依赖注入 AOP.rar

    java 无需数据库 简单实例 如何实现Spring依赖注入 AOP

    AOP编程模式与标准java的应用

    讲述了aop产生的北京,以及分析了aop应用场景。同时用一段标准java代码实现了简单的aop模式模型。

    【源码:AopFk】如何使用 Java 编写一个简单的 AOP 框架

    标题: 如何使用 Java 编写一个简单的 AOP 框架 作者: 超逮虾户 摘要: AOP(Aspect-Oriented Programming,面向切面编程)是一种编程范式,它允许程序员以模块化的方式添加功能到应用程序。AOP 框架通过在程序...

    spring aop 实现源代码--xml and annotation(带lib包)

    在Spring1.2或之前的版本中,实现AOP的传统方式就是通过实现Spring的AOP API来定义Advice,并设置代理对象。Spring根据Adivce加入到业务流程的时机的不同,提供了四种不同的Advice:Before Advice、After Advice、...

    Java Framework 关于IOC、AOP、Log的案例源码

    该源码是课程 Java Spring案例精讲 ---- Spring框架 的源码,包含Java Spring的最简单的Hello World、IOC、AOP及Log的源码 Spring整体框架中的核心功能,例如:IOC、AOP、Bean生命周期、上下文、作用域、资源处理等...

    Java核心库实现简单的AOP

    主要介绍了如何用Java核心库实现简单的AOP,帮助大家为了更好的理解和学习AOP的思想,感兴趣的朋友可以了解下

Global site tag (gtag.js) - Google Analytics