首先读者务必要理解第二篇的内容(链接描述),否则你很难理解这篇文章。
让我们再做一个动态代理的例子,你就马上能够能够理解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的整个过程。
共同学习,写下你的评论
评论加载中...
作者其他优质文章