手记

第三篇:从Java基础谈Spring AOP--动态代理原理分析AOP技术

首先读者务必要理解第二篇的内容(链接描述),否则你很难理解这篇文章。
让我们再做一个动态代理的例子,你就马上能够能够理解AOP是个啥东西。好让我们开始定义一个Javabean,它十分简单,也不需要我多做解释:

package com.learn.chapter1.aop;

/**
 *
 * @author ykzhen2015
 */
public class ConfigBean {

    private boolean flag = false;//标记代理对象是否使用这个类进行处理.
    private boolean useAround = false;//是否启用环绕通知

    public void before() {
        System.err.println("前置消息");
    }

    public void after() {
        System.err.println("后置消息");
    }

    public void afterReturn() {
        System.err.println("正常返回后的消息");
    }

    public void afterThrowing() {
        System.err.println("返回后的消息");
    }

    public Object around() {
        System.err.println("环绕通知");
        return null;
    }

    public boolean isFlag() {
        return flag;
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }

    public boolean isUseAround() {
        return useAround;
    }

    public void setUseAround(boolean useAround) {
        this.useAround = useAround;
    }
}

细心的读者就看到了,正是我们AOP看到的前置消息,后置消息,环绕消息,正常返回后的消息,异常返回消息。外加一个flag标记,它的作用就等同于一个切点,至于什么叫切点,这里放放,不用管它,我们就知道它是个boolean值,是个开关就成了,而useAround意思是是否启用环绕通知,也是一个开关。
跟着就是上篇,你们熟悉的两个类,一个十分简单的接口和实现类:

package com.learn.chapter1.aop;

/**
 *  @author ykzhen2015
 */
public interface HelloService {

    public void sayHello(String name);
}

实现类:

package com.learn.chapter1.aop;

/**
 *
 * @author ykzhen2015
 */
public class HelloServiceImpl implements HelloService {

    @Override
    public void sayHello(String name) {
        System.err.println("hello " + name);
    }
}

实现类也很简单,跟着我们改写一些我们上篇谈到的代理类,还是两个步骤:

  • 绑定HelloServiceImpl生成代理类
  • 实现代理方法
    代码如下:
package com.learn.chapter1.aop;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * * * @author ykzhen2015.
 */
public class HelloProxy implements InvocationHandler {

    private ConfigBean configBean = null;

    private Object target;

    /**
     * * 生成代理对象,并和真实服务对象绑定. * @param target 真实服务对线下 * @return 代理对象
     */
    public Object bind(Object target) {
        this.target = target; //生成代理对象,并绑定. 
        Object proxy = Proxy.newProxyInstance(target.getClass().getClassLoader(), //类的加载器 
                target.getClass().getInterfaces(), //对象的接口,明确代理对象挂在哪些接口下 
                this);//指明代理类,this代表用当前类对象,那么就要求其实现InvocationHandler接口 
        return proxy;
    }

    /**
     * * 当生成代理对象时,第三个指定使用HelloProxy进行代理时,代理对象调用的方法就会进入这个方法。
     *
     * @param proxy ——代理对象
     * @param method -- 被调用的方法
     * @param args -- 方法参数
     * @return 代理方法返回。
     * * @throws Throwable -- 异常处理
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        ConfigBean config = this.getConfigBean();
        if (!config.isFlag()) {//切点
            return method.invoke(target, args);
        }
        config.before();//前置消息
        Object obj = null;
        try {
             if (config.isUseAround()) {
                 obj = config.around();//环绕通知
             } else {
                 obj = method.invoke(target, args);//相当于sayHello方法调用.
             }
        } catch(Exception ex) {
            config.afterThrowing();//返回异常消息
        }
        config.after();//后置通知
        return obj;
    }

    public ConfigBean getConfigBean() {
        return configBean;
    }

    public void setConfigBean(ConfigBean configBean) {
        this.configBean = configBean;
    }
}

好了,这个bind方法我们上篇论述过了,我们关注的是Invoke方法。
1、首先获取一个ConfigBean,(如果是Spring就是拦截器)
2、其次判断是否启用一个ConfigBean进行处理(Spring切点判断,它一般用正则式,大同小异),如果不用则直接反射真实对象HelloService的sayHello方法,完成任务,如果用,则走第3步
3、启动前置通知before(Spring也是一样)
4、进入try ... catch...,如果环绕通知标志为true(spring是判断有没有环绕通知),则执行环绕通知;否则就反射被代理对象的方法。(Spring也是一样)
5、反射后,可能发生异常或者不发生,不发生就进入afterReturn方法,正常返回通知;发生异常就进入afterThrowing方法,异常返回通知。(Spring也是一样)
6、最后执行后置通知after方法,完成整个AOP的过程。(Spring也是一样)

好了,上面就大概是Spring执行各类通知的过程,怎么样在动态代理的分析是不是比教科书的还要清晰?
最后我们测试一下这段代码:

package com.learn.chapter1.aop;

/**
 *
 * @author ykzhen2015
 */
public class AopMain {
    public static void main(String[] args) {
        HelloProxy helloProxy = new HelloProxy();
        HelloService helloService = (HelloService) helloProxy.bind(new HelloServiceImpl());
        ConfigBean config = new ConfigBean();
        config.setFlag(true);
        config.setUseAround(true);
        helloProxy.setConfigBean(config);
        helloService.sayHello("张三");
    }
}

好看看执行结果:

前置消息
环绕通知
后置消息

在Spring的AOP中你拿到的就类似于这里的代理对象——proxy,进行了动态代理。好了这里分析了,切点,各类消息它们执行的过程,下一篇我们会更深入的讨论AOP的原理,不过到这里你已经基本掌握了AOP的整个过程。

29人推荐
随时随地看视频
慕课网APP

热门评论

什么时候出下一篇,期待

通俗易懂,开发者就需要这样的文章

期待下一篇...........

查看全部评论