使用Java原生代理实现AOP
### 本文由博主柒。原创,转载请注明出处
### 完整源码下载地址 [https://github.com/MatrixSeven/JavaAOP](https://github.com/MatrixSeven/JavaAOP)
一说到AOP,大家一定会想到Spring,因为这东西实在是太强大了.但是大家一定要清楚,AOP是一只编程思想,而Spring仅仅是AOP的一种实现罢了.
首先百度下:
在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
如果你对AOP还没有了解请左移百度百科:[http://baike.baidu.com/search/word?word=AOP](http://baike.baidu.com/search/word?word=AOP查看)查看.
今天呢,咱们就一起用Java原生代理实现简单的AOP功能.
首先,你得需要了解基本的反射知识,否则可能会感到困惑.
不罗嗦了,直接开始撸码
首先,咱们先写一个简单的接口.名字叫AnimalInterface,用来声明规范动物的一些基本方法.
这些方法包括 设置名字,获取名字,叫声,属性(原谅我没文化,其实就是获得是陆栖还是水栖或者水陆两栖)
```Java
package proxy.imp;
public interface AnimalInterface {
//设置名字
void setName(String name);
//获取名字
String getName();
//叫声
void say();
//获取栖性
void getProperty();
}
```
然后咱们实现这个接口,创建一个名叫小黑的Dog
```Java
package proxy;
import proxy.imp.AnimalInterface;
public class DogImp implements AnimalInterface {
private String name = "小黑";
public DogImp() {
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public String getName() {
return this.name;
}
@Override
public void say() {
System.out.println("小狗:汪汪汪汪.....");
}
@Override
public void getProperty() {
System.out.println("小狗是陆地动物,但是会游泳哦");
}
}
```
大家一定迫不及待了,怎么实现类似AOP的功能呢….
咱们先创建一个名为AOPHandle的类,让其实现InvocationHandler接口,
不能使用invoke时使用proxy作为反射参数时,因为代理对象的接口,不同于对象,
这种代理机制是面向接口,而不是面向类的,如果使用proxy,会造成无限递归.然后就是栈溢出,但是依旧能反射成功一次,
这说明代理对象和对象的代理是不一样的,但是咱们可以通过proxy参数的proxy.getClass()获得class对象,然后获得被代理
类的方法和参数,这也为注解注入,特定方法注入,属性注入提供了一种实现途径吧,关于这个,咱们后面再说..
```Java
package proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class AOPHandle implements InvocationHandler{
//保存对象
private Object o;
public AOPHandle(Object o) {
this.o=o;
}
/**
* 这个方法会自动调用,Java动态代理机制
* 会传入下面是个参数
* @param Object proxy 代理对象的接口,不同于对象
* @param Method method 被调用方法
* @param Object[] args 方法参数
* 不能使用invoke时使用proxy作为反射参数时,因为代理对象的接口,不同于对象
* 这种代理机制是面向接口,而不是面向类的
**/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//方法返回值
Object ret=null;
//打印方法名称
System.err.println("执行方法:"+method.getName()+"n参数类型为:");
//打印参数
for(Class type:method.getParameterTypes())
System.err.println(type.getName());
//打印返回类型
System.err.println("返回数据类型:"+method.getReturnType().getName());
//反射调用方法
ret=method.invoke(o, args);
//声明结束
System.err.println("方法执行结束");
//返回反射调用方法的返回值
return ret;
}
}
```
动态代理已经搞定..然后就是咱们的AnimalFactory了..咱们继续
```java
package proxy;
import java.lang.reflect.Proxy;
public class AnimalFactory {
/***
* 获取对象方法
* @param obj
* @return
*/
private static Object getAnimalBase(Object obj){
//获取代理对象
return Proxy.newProxyInstance(obj.getClass().getClassLoader(),
obj.getClass().getInterfaces(), new AOPHandle(obj));
}
/***
* 获取对象方法
* @param obj
* @return
*/
@SuppressWarnings("unchecked")
public static T getAnimal(Object obj){
return (T) getAnimalBase(obj);
}
/***
* 获取对象方法
* @param className
* @return
*/
@SuppressWarnings("unchecked")
public static T getAnimal(String className){
Object obj=null;
try {
obj= getAnimalBase(Class.forName(className).newInstance());
} catch (Exception e) {
e.printStackTrace();
}
return (T)obj;
}
/***
* 获取对象方法
* @param clz
* @return
*/
@SuppressWarnings("unchecked")
public static T getAnimal(Class clz){
Object obj=null;
try {
obj= getAnimalBase(clz.newInstance());
} catch (Exception e) {
e.printStackTrace();
}
return (T)obj;
}
}
```
终于到最后了…还差什么呢,大家来这里看看效果吧…
哈哈…小二,上个菜..哦~不对,是个测试类..哈哈////
```java
package proxy;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.BlockJUnit4ClassRunner;
import proxy.AnimalFactory;
import proxy.imp.AnimalInterface;
@RunWith(BlockJUnit4ClassRunner.class)
public class AOPTest {
@Test
public void Test1() {
AnimalInterface dog=AnimalFactory.getAnimal(DogImp.class);
dog.say();
System.out.println("我的名字是"+dog.getName());
dog.setName("二狗子");
System.out.println("我的名字是"+dog.getName());
}
}
```
对,咱们的效果已经看到了..
,咦,你会说没图没真相???
好,那就上图…
```java
图片在sae上已经丢失,请大家脑补
```
啥?什么,,到了最后说,,这又卵用,这不是坑爹么?就捕获一个这个玩意,什么用啊…
什么AOP,我怎么一点AOP的影子都没有看到,怎么切入自定义方法,就一个syso输入,往这忽悠观众来了?…..
好吧,那咱们继续…看看如何实现注入自定义方法…
首先增加一个接口,咱们就称为AOP注入接口吧.取名AOPMethod哈
创建after和before方法,接收Object proxy, Method method, Object[] args参数
这样就能做更多的事情叻…比如执行方法前,记录类状态,写入log.监控xx变量,,,
开启你的脑洞吧.
```java
package proxy.imp;
import java.lang.reflect.Method;
public interface AOPMethod{
//实例方法执行前执行的方法
void after(Object proxy, Method method, Object[] args);
//实例方法执行后执行的方法
void before(Object proxy, Method method, Object[] args);
}
```
然后修改AOPHandle类,增加AOPMethod属性.
在修改构造方法,让在类初始化时获得AOPMethod实例.
最后修改invoke方法….直接上代码哈
```java
package proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import proxy.imp.AOPMethod;
public class AOPHandle implements InvocationHandler{
//保存对象
private AOPMethod method;
private Object o;
public AOPHandle(Object o,AOPMethod method) {
this.o=o;
this.method=method;
}
/**
* 这个方法会自动调用,Java动态代理机制
* 会传入下面是个参数
* @param Object proxy 代理对象的接口,不同于对象
* @param Method method 被调用方法
* @param Object[] args 方法参数
* 不能使用invoke时使用proxy作为反射参数时,因为代理对象的接口,不同于对象
* 这种代理机制是面向接口,而不是面向类的
**/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object ret=null;
//修改的地方在这里哦
this.method.before(proxy, method, args);
ret=method.invoke(o, args);
//修改的地方在这里哦
this.method.after(proxy, method, args);
return ret;
}
}
```
呼呼,大功告成,,看起来一切都么问题,萌萌哒..
赶紧更新下测试类…
```java
package proxy;
import java.lang.reflect.Method;
import org.junit.runner.RunWith;
import org.junit.runners.BlockJUnit4ClassRunner;
import proxy.imp.AOPMethod;
import proxy.imp.AnimalInterface;
@RunWith(BlockJUnit4ClassRunner.class)
public class AOPTest {
public static void main(String[] args) {
AnimalInterface dog = AnimalFactory.getAnimal(DogImp.class, new AOPMethod() {
// 这里写方法执行前的AOP切入方法
public void before(Object proxy, Method method, Object[] args) {
System.err.println("我在" + method.getName() + "方法执行前执行");
}
// 这里系方法执行后的AOP切入方法
public void after(Object proxy, Method method, Object[] args) {
System.err.println("我在 " + method.getName() + "方法执行后执行");
}
});
dog.say();
String name1="我的名字是" + dog.getName();
System.out.println(name1);
dog.setName("二狗子");
String name2="我的名字是"+dog.getName();
System.out.println(name2);
}
}
```
来个效果图:
```java
图片在sae上已经丢失,请大家脑补
```
呼呼,亲们,是不是有注入的感觉了?是不是感觉把自己的方法切进去了???哈哈….
看起来一切都已经完美了,但是总觉得差了点什么?哦,对,缺少了类似于Spring那么样的配置文件..
其实那些已经很简单了,交给你们去做吧,设计好XML格式化就妥了,等等,你说什么,还不能拦截自定义方法?
不能像Spring那样拦截自定义方法?oh~~NO,其实已经可以了在
before(Object proxy, Method method, Object[] args)
中利用method和的给methodName就能做判断了.
当然,本例的并没有什么实用意义,更不能个各种完善的AOP框架相比,本文仅仅为您提供一种思路,但是一定要记住,再牛的东西也是一点点积累出来的
学习了解原理,是为了更好的驾驭所掌握的知识和技能.咱再会回嘿嘿.
使用Java原生代理实现AOP的更多相关文章
- 使用Java原生代理实现数据注入
本文由博主原创,转载请注明出处 完整源码下载地址 https://github.com/MatrixSeven/JavaAOP 上一篇,咱们说了使用Java原生代理实现AOP的简单例子,然么就不得不说 ...
- Java动态代理-->Spring AOP
引述要学习Spring框架的技术内幕,必须事先掌握一些基本的Java知识,正所谓“登高必自卑,涉远必自迩”.以下几项Java知识和Spring框架息息相关,不可不学(我将通过一个系列分别介绍这些Jav ...
- Java 动态代理与AOP
动态代理与AOP 代理模式 代理模式给某一个目标对象(target)提供代理对象(proxy),并由代理对象控制对target对象的引用. 模式图: 代理模式中的角色有: 抽象对象角色(Abstrac ...
- Java 动态代理及AOP实现机制
AOP实现机制http://www.iteye.com/topic/1116696 AOP: (Aspect Oriented Programming) 面向切面编程AOP包括切面(aspect).通 ...
- [JAVA]动态代理与AOP的千丝万缕
动态代理与AOP的联系 别的不说,直接上图 首先是AOP切面编程 什么是切面?(自己心里想想就ok)所以所谓的切面编程,你也就懂得大体了,只是这个被切的是个程序而已 那么AOP与动态代理有什么关系呢? ...
- Java动态代理(AOP)
目录 一.代理 1. 什么是代理? 2. 使用代理模式的作用 3. 实现代理的方式 二.静态代理 1. 模拟用户购买u盘 2. 静态代理的缺点 三.动态代理 四. JDK 动态代理 1. Invoca ...
- Java动态代理学习【Spring AOP基础之一】
Spring AOP使用的其中一个底层技术就是Java的动态代理技术.Java的动态代理技术主要围绕两个类进行的 java.lang.reflect.InvocationHandler java.la ...
- java动态代理实现与原理详细分析(代码层面解释了AOP的实现)
关于Java中的动态代理,我们首先需要了解的是一种常用的设计模式--代理模式,而对于代理,根据创建代理类的时间点,又可以分为静态代理和动态代理. 一.代理模式 代理模式是常用的java设计模式, ...
- AOP面向切面编程JAVA动态代理实现用户权限管理(实现篇)
java动态代理机制的功能十分强大,使用动态代理技术能够有效的降低应用中各个对象之间的耦合紧密程度,提高开发的效率以及程序的可维护性,事实上Spring AOP就是建立在Java动态代理的基础之上.其 ...
随机推荐
- Hello Web API系列教程——Web API与国际化
软件国际化是在软件设计和文档开发过程中,使得功能和代码设计能处理多种语言和文化习俗,在创建不同语言版本时,不需要重新设计源程序代码的软件工程方法.这在很多成熟的软件开发平台中非常常见.对于.net开发 ...
- EntityFramework之DetectChanges's Secrets(三)(我为EF正名)
前言 对于应用程序开发者来说,通常不需要考虑太多对于Entity Framework中的变更追踪(change tracking),但是变更追踪和DetectChanges方法是栈的一部分,在这其中, ...
- nodejs利用http模块实现银行卡所属银行查询和骚扰电话验证
http模块内部封装了http服务器和客户端,因此Node.js不需要借助Apache.IIS.Nginx.Tomcat等传统HTTP服务器,就可以构建http服务器,亦可以用来做一些爬虫.下面简单介 ...
- JS判断鼠标进入容器方向的方法和分析window.open新窗口被拦截的问题
1.鼠标进入容器方向的判定 判断鼠标从哪个方向进入元素容器是一个经常碰到的问题,如何来判断呢?首先想到的是:获取鼠标的位置,然后经过一大堆的if..else逻辑来确定.这样的做法比较繁琐,下面介绍两种 ...
- ASP.NET Core project.json imports 是什么意思?
示例代码: "frameworks": { "netcoreapp1.0.0": { "imports" : "portable- ...
- jQuery.template.js 简单使用
之前看了一篇文章<我们为什么要尝试前后端分离>,深有同感,并有了下面的评论: 我最近也和前端同事在讨论这个问题,比如有时候前端写好页面给后端了,然后后端把这些页面拆分成很多的 views, ...
- Android 几种消息推送方案总结
转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/6241354.html 首先看一张国内Top500 Android应用中它们用到的第三方推送以及所占数量: 现 ...
- MATLAB中绘制质点轨迹动图并保存成GIF
工作需要在MATLAB中绘制质点轨迹并保存成GIF以便展示. 绘制质点轨迹动图可用comet和comet3命令,使用例子如下: t = 0:.01:2*pi;x = cos(2*t).*(cos(t) ...
- 免费道路 bzoj 3624
免费道路(1s 128MB)roads [输入样例] 5 7 21 3 04 5 13 2 05 3 14 3 01 2 14 2 1 [输出样例] 3 2 04 3 05 3 11 2 1 题解: ...
- 去IOE的一点反对意见以及其他
某天在机场听见两老板在聊天,说到他们目前销售的报表老跟不上的问题,说要请一个人,专门合并和分析一些发过来的excel表格,我真想冲上去说,老板,你需要的是一个信息处理的系统,你需要咨询么.回来一直耿耿 ...