时光如梭,转眼之间,春招已然结束,秋招正在赶来,又到了技术布道的时候了。。
今天简单的聊一聊AOP(Aspect Oriented Programming)
起因
项目中需要查看一些方法前后的运行时间,以便合理的推测出代码是否能够扛得住XXQPS的访问。要是每个方法前后都写一个时间减法,那可真是个累活了,于是AOP思想出来了。。
通过一个条件来匹配想要拦截的代码,这个条件在AOP中就是PointCut(切点)
切点搞定之后,只需要再做一个切面(即定义拦截后的操作)就行了。
简单的实现AOP
假设现在有一个需求:
interface Passing{
void Time_Consume(String name);
}
在这个接口前面和后面都打印出特定的字符串
方法一:写死代码
interface Passing{
void Time_Consume(String name);
}
class PassingImpl implements Passing{
public void Time_Consume(String name){
before();
System.out.println("the time:"+name);
after();
}
private void before(){
System.out.println("Before");
}
private void after(){
System.out.println("After");
}
}
public class Hello {
public static void main(String []args){
// System.out.println("Hello world");
new PassingImpl().Time_Consume("Now");
}
}
如果只有一个方法那还好说,但是万一每个方法都要有这个需求,那工作量可就完蛋了,所以AOP来了。
一般可以有以下三种解决方案:
* 静态代理
* JDK动态代理
* CGLIB动态代理
静态代理
interface Passing{
void Time_Consume(String name);
}
class PassingImpl implements Passing{
public void Time_Consume(String name){
before();
System.out.println("the time:"+name);
after();
}
private void before(){
System.out.println("Before");
}
private void after(){
System.out.println("After");
}
}
class PassingProxy implements Passing{
private PassingImpl passingImpl;
public PassingProxy(PassingImpl passingImpl){
this.passingImpl=passingImpl;
}
@Override
public void Time_Consume(String name){
before();
passingImpl.Time_Consume(name);
after();
}
private void before(){
System.out.println("Before");
}
private void after(){
System.out.println("After");
}
}
public class Hello {
public static void main(String []args){
// System.out.println("Hello world");
// new PassingImpl().Time_Consume("Now");
Passing passingProxy=new PassingProxy(new PassingImpl());
passingProxy.Time_Consume("Now");
}
}
静态代理看起来还是不错的,但是如果我想多代理几个其他的,那还得为其他的几个量身定做几个,这重复劳动要不得,所以就有了接下来的JDK动态代理。
JDK动态代理
class JDKDynamicProxy implements InvocationHandler{
private Object target;
public JDKDynamicProxy(Object target){
this.target=target;
}
public <T> T getProxy(){
return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this::invoke);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object result=method.invoke(target,args);
after();
return result;
}
private void before(){
System.out.println("Before");
}
private void after(){
System.out.println("After");
}
}
public class Hello {
public static void main(String []args){
// System.out.println("Hello world");
// new PassingImpl().Time_Consume("Now");
// Passing passingProxy=new PassingProxy(new PassingImpl());
// passingProxy.Time_Consume("Now");
Passing passing=new JDKDynamicProxy(new PassingImpl()).getProxy();
passing.Time_Consume("Now");
}
}
如此这般,所有的代理类都能够合并到动态代理类中,还是得感谢泛型,但是这样做有一个问题:JDK的动态代理只能够提供有代理接口的,不能代理没有接口的类,这下麻烦大了,万一项目中就是需要代理没有接口的类该咋办呢。CGLib动态代理!
CGLib动态代理
使用开源的CGLiB类库可以代理没有接口的类,这样就完美解决了上述问题,该代理以后有时间再详细研究研究
Spring AOP:
AOP框架可以理解为一个拦截器框架,只需要拦截特定的方法即可,这个时候切面(AOP的实现方式) 就是AOP的核心,即给出如何拦截的方式,说白了就是通过切面,将拦截匹配的条件组合在一起,然后 将这个切面配置到ProxyFactory中,从而生成代理。
最后附上一张AOP思维导图
小结
感谢本书《架构探险》,AOP确实值得好好的研究研究。