-
背景
想要了解Spring框架,那可以说AOP(面向切面编程)是必须要了解的。为此,查阅了很多资料,看过了很多网上的很多介绍,还是没有给我满意的答案,最终在一名老师(铁血教主)的指导下,才真正了解到了内部看似复杂无比的架构。AOP在如今的很多大型项目中都有涉及,主要为了解决添加日志,安全检查,权限管理等的问题。简单来说,就是利用代理,对某些方法的执行进行拦截或者管理。
-
原理
AOP其实就是利用代理机制对一个类形成一个代理对象,然后使用这个代理对象执行方法。有人可能问了,这有什么用?用处大了,利用代理对象执行原方法,我们便可以对代理对象进行限制,在其调用方法时加以控制。那为什么不直接对原对象控制呢?个人理解是这样的。使用代理的话,原类可以专心实现他的功能,而把权限管理,安全检查等问题,在外部实现,达到互不干涉却又可以共同工作的目的。
由于AOP主要依靠的便是代理机制,而我们最常用的代理便是JDKProxy和CGLIBProxy,这两种代理各有利弊,可以用于不同的场合。
JDKProxy: 指定类必须要实现一个接口,也就是说,如果被代理对象已经封装好,不能修改,那么就不能使用这个代理。并且由于返回的是一个接口对象,使得代理仅仅能够执行接口中的方法。
@SuppressWarnings("unchecked")
private <T> T jdkProxy(Object object, Class<?> klass) {
ClassLoader classLoader = klass.getClassLoader();
Class<?>[] interfaces = klass.getInterfaces();
InvocationHandler invocationHandler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return doInvoker(object, method, args);
}
};
return (T) Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
}
CGLIBProxy: 这个代理不需要实现接口,它的实现思想是用原类作为基类,用派生类的对象去执行方法。是不是感觉这个代理还是很不错的,当然,也有局限性,其一,原类必须拥有无参构造方法,也就是说允许继承。其二,原类的final方法不能被继承,那么代理也就不能执行final方法。
@SuppressWarnings("unchecked")
private <T> T cglProxy(Object object, Class<?> klass) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(klass);
MethodInterceptor methodInterceptor = new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
return doInvoker(object, method, args);
}
};
enhancer.setCallback(methodInterceptor);
return (T) enhancer.create();
}
两种方法各有利弊,适用于不同的场合。不过大多数情况我们使用的还是CGLIBProxy。
-
注意事项
用代理对象执行方法时,调用原类中的方法的对象还是原对象,不是代理,这里给大家用代码加以验证。
我们现在这个方法里输出this,便可以看到,执行该方法的到底是谁?
public int getNum() {
System.out.println("this.getClass():" + this.getClass());
return num;
}
NormalClass normalClass = new NormalClass();//这是一个普通类,里面只有一个num成员
normalClass.setNum(123);
NormalClass normalClassProxy = new CGLibProxy().getProxy(normalClass);
System.out.println("原对象的num" + normalClass.getNum());
System.out.println("normalClass.getClass():" + normalClass.getClass());
System.out.println("代理对象的num" + normalClassProxy.getNum());
System.out.println("normalClassProxy.getClass()" + normalClassProxy.getClass());
很明显可以看出,用代理执行该方法,在执行到该方法时,是原对象调用,不是代理在调用。这点必须清楚,而非原类的方法,才是代理调用。
-
大体框架介绍
好了,这才开始正式说AOP。先大概说一下整体的设计思路
-
代码是最好的老师
首先给出ProxyFactory的实现方式,这里其实是将两种代理的获取方式都放在factory里,没什么难度。但这里需要注意,每次代理生成的时候,要自动将生成一个ProxyPackage对象,并将代理注入。
public class ProxyFactory {
private ProxyPackage proxyPackage;
ProxyFactory() {
}
ProxyPackage getproxyPackage() {
return proxyPackage;
}
//这里在每次取得代理时,会自动生成proxyPackage对象,无需手动生成,方便以后的map的put
<T> T getCGLProxy(Object object, Class<?> klass) {
T proxy = cglProxy(object, klass);
proxyPackage = new ProxyPackage();
proxyPackage.setProxy(proxy);
proxyPackage.setObject(object);
return proxy;
}
@SuppressWarnings("unchecked")
private <T> T cglProxy(Object object, Class<?> klass) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(klass);
MethodInterceptor methodInterceptor = new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
return doInvoker(object, method, args);
}
};
enhancer.setCallback(methodInterceptor);
return (T) enhancer.create();
}
//这里的DOInvoke()方法,在proxyPackage中实现
private Object doInvoker(Object object, Method method, Object[] args) throws Throwable {
Object result = null;
// 前置拦截
if (proxyPackage.doBefore(method, args) == false) {
return null;
}
try {
result = method.invoke(object, args);
// 后置拦截
proxyPackage.doAfter(method, result);
} catch (Throwable e) {
// 异常拦截
proxyPackage.doDealException(method, e);
throw e;
}
return result;
}
<T> T getJDKProxy(Object object, Class<?> klass) {
T proxy = jdkProxy(object, klass);
proxyPackage = new ProxyPackage();
proxyPackage.setProxy(proxy);
return proxy;
}
@SuppressWarnings("unchecked")
private <T> T jdkProxy(Object object, Class<?> klass) {
ClassLoader classLoader = klass.getClassLoader();
Class<?>[] interfaces = klass.getInterfaces();
InvocationHandler invocationHandler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return doInvoker(object, method, args);
}
};
return (T) Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
}
这就是要封装成的代理类,每一个代理要附带这个代理需要的拦截器。当用这个代理执行方法 时,要一层层通过拦截器的审核。我们在实现时,主要加了置前拦截,置后拦截,异常拦截,当然这只是在Test。
public class ProxyPackage {
private Object proxy; //取得的代理
private Object object; //原对象
private boolean injection; //这是为了之后的ioc做准备的,可以先不考虑
private List<Intercepter> intercepterList;
ProxyPackage() {
this.intercepterList = new ArrayList<>();
injection = false;
}
Object getObject() {
return object;
}
boolean isInjection() {
return injection;
}
void setInjection(boolean injection) {
this.injection = injection;
}
void setObject(Object object) {
this.object = object;
}
void addIntercepter(Intercepter intercepter)
throws IntercepterAlreadyExistException {
if (intercepterList.contains(intercepter)) {
String intercepterName = intercepter.getClass().getName();
throw new IntercepterAlreadyExistException("拦截器("
+ intercepterName + ")已存在!");
}
intercepterList.add(intercepter);
}
void removeIntercepter(Intercepter intercepter) {
if (!intercepterList.contains(intercepter)) {
return;
}
intercepterList.remove(intercepter);
}
boolean doBefore(Method method, Object[] args) {
for (Intercepter intercepter : intercepterList) {
if (!intercepter.getMethod().equals(method)) {
continue;
}
if (intercepter.before(args) == false) {
return false;
}
}
return true;
}
Object doAfter(Method method, Object result) {
for (Intercepter intercepter : intercepterList) {
if (!intercepter.getMethod().equals(method)) {
continue;
}
result = intercepter.after(result);
}
return result;
}
void doDealException(Method method, Throwable e) {
for (Intercepter intercepter : intercepterList) {
if (!intercepter.getMethod().equals(method)) {
continue;
}
intercepter.dealException(e);
}
}
<T> ProxyPackage setProxy(T proxy) {
this.proxy = proxy;
return this;
}
@SuppressWarnings("unchecked")
<T> T getProxy() {
return (T) proxy;
}
每一个拦截器对象要注明klass和method.用来标注是为那个指定方法加的拦截器。
public abstract class Intercepter {
private Class<?> klass;
private Method method;
public Intercepter() {
}
public Intercepter(Class<?> klass, Method method) {
this.klass = klass;
this.method = method;
}
public abstract boolean before(Object[] args);
public abstract Object after(Object reault);
public abstract void dealException(Throwable e);
public void setMethod(Method method) {
this.method = method;
}
public Method getMethod() {
return method;
}
public void setKlass(Class<?> klass) {
this.klass = klass;
}
public Class<?> getKlass() {
return klass;
}
给出适配器,让用户选择性覆盖使用。
public class IntercepterAdapter extends Intercepter {
public IntercepterAdapter() {
}
public IntercepterAdapter(Class<?> klass, Method method) {
super(klass, method);
}
@Override
public boolean before(Object[] args) {
return true;
}
@Override
public Object after(Object result) {
return result;
}
@Override
public void dealException(Throwable e) {
}
最后将给一个map来装每一个类的代理,方便以后使用。这里要注意,我们只考虑了单例模式,至于多例模式,见后文。
public class ProxyBeanFactory {
private static final Map<String, String> beanNameMap;//这是IOC要用的,这里先不做叙述
private static final Map<String, ProxyPackage> beanMap;
static {
beanMap = new HashMap<>();
beanNameMap = new HashMap<>();
}
protected ProxyBeanFactory() {
}
protected void addBeanName(String beanName, String className)
throws Exception {
String orgClassName = beanNameMap.get(beanName);
if (orgClassName != null) {
throw new BeanNameAlreadyExistException("Bean名称("
+ beanName + ")重复!");
}
beanNameMap.put(beanName, className);
}
protected String getBeanClassName(String beanName) {
return beanNameMap.get(beanName);
}
protected void createCGLProxy(Object object) throws Exception {
cglProxy(object, object.getClass());
}
protected void createCGLProxy(Class<?> klass) throws Exception {
cglProxy(klass.newInstance(), klass);
}
protected ProxyPackage getMecProxy(String className) {
return beanMap.get(className);
}
protected <T> T getProxy(Class<?> klass) {
ProxyPackage mecProxy = beanMap.get(klass.getName());
if (mecProxy == null) {
return null;
}
return mecProxy.getProxy();
}
private void cglProxy(Object object, Class<?> klass) throws Exception {
String className = klass.getName();
ProxyPackage mecProxy = beanMap.get(className);
if (mecProxy != null) {
// TODO 应该抛异常
return;
}
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.getCGLProxy(object, klass);
beanMap.put(className, proxyFactory.getproxyPackage());
return;
}
protected <T> T getJDKProxy(Object object) throws Exception {
return jdkProxy(object, object.getClass());
}
protected <T> T getJDKProxy(Class<?> klass) throws Exception {
return jdkProxy(klass.newInstance(), klass);
}
private <T> T jdkProxy(Object object, Class<?> klass) throws Exception {
String className = klass.getName();
ProxyPackage mecProxy = beanMap.get(className);
if (mecProxy != null) {
return mecProxy.getProxy();
}
ProxyFactory proxyFactory = new ProxyFactory();
T proxy = proxyFactory.getJDKProxy(object, klass);
beanMap.put(className, proxyFactory.getproxyPackage());
return proxy;
}
protected void addIntercepter(Class<?> klass, Intercepter intercepter)
throws Exception {
if (!intercepter.getKlass().equals(klass)) {
return;
}
beanMap.get(klass.getName()).addIntercepter(intercepter);
}
protected void removeIntercepter(Class<?> klass, Intercepter intercepter) {
beanMap.get(klass.getName()).removeIntercepter(intercepter);
}
写了这么多,赶紧给出一个Test。
public class NormalClassIntercepter extends MecIntercepterAdapter {
public NormalClassIntercepter(Class<?> klass, Method method) {
super(klass, method);
}
public NormalClassIntercepter() {
}
@Override
public boolean before(Object[] args) {
for (Object arg : args) {
System.out.println(arg);
}
return true;
}
@Override
public Object after(Object result) {
System.out.println(result);
return result;
}
public static void main(String[] args) throws NoSuchMethodException, SecurityException {
//这是要代理的类
Class<?> klass = NormalClass.class;
Method method = klass.getDeclaredMethod("normalAction", new Class<?>[] { String.class} );
//
NormalClassIntercepter intercepter = new NormalClassIntercepter(NormalClass.class, method);
BeanFactory beanFactory = new BeanFactory();
try {
NormalClass normal = beanFactory.getCGLProxy(NormalClass.class);
beanFactory.addIntercepter(klass, intercepter);
System.out.println("函数执行结果是" + normal.normalAction("abcde"));
} catch (Exception e) {
e.printStackTrace();
}
}
这里只添加了一个拦截器,可以看到已经可以看到拦截器的雏形了。当执行原方法时,实际上上是从fatory中取得bean(这里就是代理),然后利用代理执行原方法,便可以在执行时加以控制。当然可以发现,我们拦截器的添加,实际上是需要手动添加的,可是这不是很麻烦吗。有什么简单办法呢,这是便需要IOC的引入,为我们自动扫描拦截器或者bean,并且自动注入。