Ioc之前看了一些书籍,有写概念,而AOP则基本没什么概念。感觉比较深奥,就先从这里开刀。不过看了看,感觉其实就那么回事。
一般情况下,一个方法里面除了完成业务外,肯定会加入一些其他多余的东西。。。。log(这个东西可能国外用得比较多,国内可能有这个习惯的人不多,我新手,肯定没这个习惯了。。。。),安全检查(这个应该是到处可见)。这样的话,这个方法就不‘纯’了。如果哪天你要把这写多余的东西去掉,那就要一个方法一个方法的去找。会累死人的。AOP就为解决这个问题的。
先看代码(代码都为技术手册实例,简单明了!)。
最原始也是最快速的给方法添加log的方法就像这样写。
import java.util.logging.Level;
import java.util.logging.Logger;
/*A normal java Class which will be
compared with a Class using AOP*/
public class NormalClass {
private Logger log = Logger.getLogger(this.getClass().getName());
public void hello(String name){
//log before print
log.log(Level.INFO,"hello method starts....");
//print
System.out.println("Hello," + name);
//log after print
log.log(Level.INFO,"hello method ends....");
}
}
假如100个方法都要加log,重复代码可想而知了。(英文注释自己写的,书写水平很烂,阅读水平一般,欢迎拍砖。。。。)
下面是以静态代理来实现最简单的aop。首先,定义个接口。实现类和代理类都实现此接口。
public interface SayHello {
void hello(String hello);
}
然后是实现类,里面就是最简单的业务处理---打印。
import staticproxy.inter.SayHello;
public class SayHelloImpl implements SayHello{
@Override
public void hello(String name) {
System.out.println("Hello," + name);
}
}
接着是代理类,代理类里添加log。
import java.util.logging.Level;
import java.util.logging.Logger;
import staticproxy.inter.SayHello;
public class SayHelloImplProxy implements SayHello {
private SayHello say;
private Logger log ;
public SayHelloImplProxy(SayHello say){
this.say = say;
log = Logger.getLogger(this.say.getClass().getName());
}
@Override
public void hello(String name) {
log.log(Level.INFO,"hello method starts....");
this.say.hello(name);
log.log(Level.INFO,"hello method ends....");
}
}
测试一下。
import dynamicproxy.LogHandler;
import staticproxy.SayHelloImpl;
import staticproxy.SayHelloImplProxy;
import staticproxy.inter.SayHello;
import normal.NormalClass;
public class Test {
public static void main(String[] args){
//Test normal.NormalClass
NormalClass nor = new NormalClass();
nor.hello("Ivan");
//Test staticproxy.SayHelloImpl
SayHello say = new SayHelloImplProxy(new SayHelloImpl());
say.hello("Ivan");
}
}
两个输出应该是一样的。这样就把业务和log分开了。这是代理模式的简单体现,应该很简单。不过缺点显而易见,每个类都得有个代理类。
于是就有了动态代理。直接实现java.lang.reflect.InvocationHandler接口即可。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.logging.Level;
import java.util.logging.Logger;
public class LogHandler implements InvocationHandler {
private Logger log = Logger.getLogger(this.getClass().getName());
private Object delegate;
public Object bind(Object delegate) {
this.delegate = delegate;
return Proxy.newProxyInstance(delegate.getClass().getClassLoader(),
delegate.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object res = null;
log(method + " method starts....");
res = method.invoke(delegate, args);
log.log(Level.INFO,method + " method ends....");
return res;
}
private void log(String message) {
log.log(Level.INFO,message);
}
}
看起来好像挺复杂,其实和静态代理一样。其中的bind就相当于静态代理的构造方法。然后在调用时,会自动的调用invoke方法,在invoke方法里添加了log。
其他代码和静态代理的一模一样。不重复。
这样的话,你想在哪个方法里添加log,只要bind那个类就可以了。
这就是AOP了,没什么深奥的。就实现方法有区别而已。Spring里的AOP就是用动态代理实现的。
下面通过上面的代码解释几个AOP的名词。
1.Cross-cutting concern(直译应该叫“横切关注点”)
我理解的就是,需要以AOP来处理的东东。像log,安全检查这些。
2.Aspect(方面)
就是对于那些横切关注点所编写的类。如LogHandler。
3.Advice(原意“忠告”,感觉莫名其妙。)
可以理解为,在Aspect里面,实现的Cross-cutting concern的具体方法.如Loghandler里的invoke方法。
4.Joinpoint
Advice被执行的那个时机。(感觉比较抽象。保留意见。)
5.Pointcut
可以理解为Joinpoint执行的条件,符合Pointcut的Joinpoint才执行。
6.Target
简单理解为被代理的那个对象。如SayHelloImpl。
7.Introduction
给一个已编写或编译玩的类,在执行期间动态地加入一些方法或行为,而不修改或新增任何一行程序代码。(不解其意。。。。不是不懂他说的意思,而是不解,他说的是Introduction这个东东的功能还是什么。)
8.Proxy(代理)
。。。。
9.Weave(编织,组合,编排)
Advice被应用至对象之上的过程称之为Weave。