使用Java原生代理实现AOP

本文由博主林小柒原创,转载请注明出处
完整源码下载地址 https://github.com/MatrixSeven/JavaAOP

出处:http://www.zhaoguilin.com
一说到AOP,大家一定会想到Spring,因为这东西实在是太强大了.但是大家一定要清楚,AOP是一只编程思想,而Spring仅仅是AOP的一种实现罢了.

首先百度下:

在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

如果你对AOP还没有了解请左移百度百科:http://baike.baidu.com/search/word?word=AOP查看.

今天呢,咱们就一起用Java原生代理实现简单的AOP功能.

首先,你得需要了解基本的反射知识,否则可能会感到困惑.

不罗嗦了,直接开始撸码

首先,咱们先写一个简单的接口.名字叫AnimalInterface,用来声明规范动物的一些基本方法.

这些方法包括 设置名字,获取名字,叫声,属性(原谅我没文化,其实就是获得是陆栖还是水栖或者水陆两栖)


1

2

3

4

5

6

7

8

9

10

11

12

package proxy.imp;

public interface AnimalInterface {

    //设置名字

    void setName(String name);

    //获取名字

    String getName();

    //叫声

    void say();

    //获取栖性

    void getProperty();

}

然后咱们实现这个接口,创建一个名叫小黑的Dog


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

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对象,然后获得被代理
类的方法和参数,这也为注解注入,特定方法注入,属性注入提供了一种实现途径吧,关于这个,咱们后面再说..


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

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了..咱们继续.


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

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;

    }

}

终于到最后了…还差什么呢,大家来这里看看效果吧…
哈哈…小二,上个菜..哦~不对,是个测试类..哈哈////


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

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());

    }

}

对,咱们的效果已经看到了..
,咦,你会说没图没真相???
好,那就上图…

啥?什么,,到了最后说,,这又卵用,这不是坑爹么?就捕获一个这个玩意,什么用啊…
什么AOP,我怎么一点AOP的影子都没有看到,怎么切入自定义方法,就一个syso输入,往这忽悠观众来了?…..
好吧,那咱们继续…看看如何实现注入自定义方法…

首先增加一个接口,咱们就称为AOP注入接口吧.取名AOPMethod哈
创建after和before方法,接收Object proxy, Method method, Object[] args参数
这样就能做更多的事情叻…比如执行方法前,记录类状态,写入log.监控xx变量,,,
开启你的脑洞吧.


1

2

3

4

5

6

7

8

9

10

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方法….直接上代码哈


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

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;

    }

}

呼呼,大功告成,,看起来一切都么问题,萌萌哒..
赶紧更新下测试类…


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

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.classnew 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);

    }

}

来个效果图:

呼呼,亲们,是不是有注入的感觉了?是不是感觉把自己的方法切进去了???哈哈….

看起来一切都已经完美了,但是总觉得差了点什么?哦,对,缺少了类似于Spring那么样的配置文件..

其实那些已经很简单了,交给你们去做吧,设计好XML格式化就妥了,等等,你说什么,还不能拦截自定义方法?

不能像Spring那样拦截自定义方法?oh~~NO,其实已经可以了在
before(Object proxy, Method method, Object[] args)
中利用method和的给methodName就能做判断了.
当然,本例的并没有什么实用意义,更不能个各种完善的AOP框架相比,本文仅仅为您提供一种思路,但是一定要记住,再牛的东西也是一点点积累出来的
学习了解原理,是为了更好的驾驭所掌握的知识和技能.咱再会回嘿嘿..

时间: 2024-12-09 22:24:35

使用Java原生代理实现AOP的相关文章

Java动态代理-->Spring AOP

引述要学习Spring框架的技术内幕,必须事先掌握一些基本的Java知识,正所谓“登高必自卑,涉远必自迩”.以下几项Java知识和Spring框架息息相关,不可不学(我将通过一个系列分别介绍这些Java基础知识,希望对大家有所帮助.): [1] Java反射知识-->Spring IoC :http://www.iteye.com/topic/1123081 [2] Java动态代理-->Spring AOP :http://www.iteye.com/topic/1123293 [3] 属性

Java动态代理实现AOP

作者:兄弟连 目前整个开发社区对AOP(Aspect Oriented Programing)推崇备至,也涌现出大量支持AOP的优秀Framework,--Spring, JAC, Jboss AOP 等等.AOP似乎一时之间成了潮流.Java初学者不禁要发出感慨,OOP还没有学通呢,又来AOP.本文不是要在理论上具体阐述何为AOP, 为何要进行AOP . 要详细了解学习AOP可以到它老家http://aosd.net去瞧瞧.这里只是意图通过一个简单的例子向初学者展示一下如何来进行AOP. 为了

java动态代理(AOP)

一.使用jdk自带的动态代理机制: 定义一个普通的接口及实现类: 定义一个InvocationHandler的实现类用于织入横向插入的操作(此处为打印信息): 生成接口的代理类: 调用接口方法,实现动态代理. package aopdemo.jdk; public interface INormalService { public void service(); } package aopdemo.jdk; public class NormalServiceImpl implements IN

【转载】Java JDK 动态代理(AOP)使用及实现原理分析

转自:http://blog.csdn.net/jiankunking/article/details/52143504 版权声明:作者:jiankunking 出处:http://blog.csdn.net/jiankunking 本文版权归作者和CSDN共有 一.什么是代理? 代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问.代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理. 代理模式UML图: 简单结构示意图: 为了保持

代理模式 & Java原生动态代理技术 & CGLib动态代理技术

第一部分.代理模式  代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务.(其实就是在代理类中关联一个委托类的实例,然后在代理类中进行包装). UML图如下: 第二部分.在Java中实现代理模式  按照代理的创建时期,代理类可以分

AOP与JAVA动态代理

1.AOP的各种实现 AOP就是面向切面编程,我们可以从以下几个层面来实现AOP 在编译期修改源代码 在运行期字节码加载前修改字节码 在运行期字节码加载后动态创建代理类的字节码 2.AOP各种实现机制的比较 以下是各种实现机制的比较: 类别 机制 原理 优点 缺点 静态AOP 静态织入 在编译期,切面直接以字节码的形式编译到目标字节码文件中 对系统无性能影响 灵活性不够 动态AOP 动态代理 在运行期,目标类加载后,为接口动态生成代理类,将切面织入到代理类中 相对于静态AOP更加灵活 切入的关注

Java代理(Aop实现的原理)

经过大牛同事的一句指点立刻明白的代理实现方式,Spring Aop应该也是这么去做的.直接上代码 实现在Car的run方法之前调用star方法,在run方法之后调用stop方法. Car类 package com.lubby.test; public class Car { public void run() { System.out.println("I am running...."); } } Car的run方法之前和之后调用的方法 package com.lubby.test;

Java使用动态代理实现AOP

参考资料: http://www.importnew.com/15420.htmlhttp://www.cnblogs.com/techyc/p/3455950.html Spring是借助了动态代理(JDK dynamic proxy)和CGlib两种技术实现AOP的,本文将学习前人的例子使用动态代理模拟AOP的特性. 1. 环境 Java: jdk1.8.0_144 2. 学习动态代理Proxy.newProxyInstance()方法 它的三个参数如下 参数名 类型 说明 loader C

java动态代理,及spring AOP

介绍:spring 的AOP (Aspect Oriented Programming)是通过java的动态代理来实现的,对于AOP不了解的朋友可以去网上看相关资料,我这里重点说明实现原理即java动态代理 要谈java动态代理就不得不说java的代理模式,我这里只给出代理模式的UML图 如图(1)及动态代理模式的UML类图 如图(2) 说明:图(2)中的红色红色斜体的类或接口是由java类库提供的即 Proxy和InvocationHandler 是java对动态代理的支持 图 (1) 和 图