github: https://github.com/iamzhubaoliang/MySpring
博客不易,希望给个star,如果有问题可以评论,也可以github issue,我会耐心解答疑惑
1. 什么是AOP
AOP就是面向切面编程,将横切服务与核心业务逻辑分离,更好关注核心业务逻辑或者说将系统级服务与具体的商业逻辑分离。AOP的实现主要实现方法是代理,Spring中使用的是原生JDK的动态代理
2. 原生JDK动态代理
原生的JDK动态代理首先代理类要实现InvocationHandler接口,并重写invoke方法,创建代理的时候将原对象传入,这样代理对象持有原对象,可以调用原对象的方法,并对某些部分进行增强
例子
接口
public interface peopleInterface {
public void runFunc();
}
实现类
public class people implements peopleInterface{
@Override
public void runFunc() {
System.out.println("方法执行");
}
}
代理类
public class JDKProxy implements InvocationHandler {
private people p;
public Object bind(people target)
{
this.p=target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("前置");
p.runFunc();
System.out.println("后置");
return null;
}
public static void main(String[] args) {
people p=new people();
JDKProxy proxy=new JDKProxy();
peopleInterface peopleInterface= (test.peopleInterface) proxy.bind(p);
peopleInterface.runFunc();
}
}
注意:原生JDK必须有接口,因为原生JDK是基于接口实现的
3.实现思路
基于上述的原生JDK的例子,基本的实现方法就是这样,那么我们怎样去做增强?这个思路就是在遍历的时候将增强的方法存入代理中,当执行方法的时候判断这个方法是否有增强,具体做法就是用一个集合来进行存储
首先我们要识别增强类,方法就是使用@Aspect注解
if (clazz.isAnnotationPresent(Aspect.class)) {
for (Method method : clazz.getMethods()) {
String annotationPath = "";
if (method.isAnnotationPresent(PointCut.class)) {
String delegateString = method.getAnnotation(PointCut.class).value();
annotationPath=delegateString;
if (delegateString.charAt(delegateString.length() - 1) == ')') {
//说明是在某个方法上面的切面
annotationPath =annotationPath.replace("()","");
//切掉方法保留到类
String[] seg=cutName(annotationPath);
AddToAspects(clazz,seg[0],true,seg[1]);
}else
{//切面是某个包或者类
String annotationPathClone=new String(annotationPath);
URL resource=Container.classLoader.getResource(annotationPathClone.replace(".","/"));
if(resource==null)
resource=Container.classLoader.getResource(annotationPathClone.replace(".","/")+".class");
File file=new File(resource.getFile());
// System.out.println(file);
if(file.isDirectory()) {
ArrayList<File> fileArray=new ArrayList<>();
DFSgetCureentDir(file,fileArray);
for(File f:fileArray)
{
String key= f.getAbsolutePath().replace(splitOP,".");
key=key.substring(key.indexOf(annotationPath),key.indexOf(f.getName())+f.getName().length()-6);
AddToAspects(clazz,key,false,"");
}
}else
{
String key= file.getAbsolutePath().replace(splitOP,".");
key=key.substring(key.indexOf(annotationPath),key.indexOf(file.getName())+file.getName().length()-6);
AddToAspects(clazz,key,false,"");
}
}
}
}
}
首先查看遍历的类是不是有Aspect注解,如果有那么遍历每一个方法寻找PointCut注解,这个注解上的value为要增强的类或者具体的方法,当有)的时候我们认为是方法,当没有的时候认为是某个包或者类,将要增强的类或者方法作为key,利用MethodNode包装方法作为value放入BeforeDelegatedSet,AfterDelegatedSet,MethodNode的作用是包装方法,里面有个boolean isFunction表明这个增强是在整个类上还是某个方法上面。
private static void AddToAspects(Class<?> clazz,String key,boolean isMethod,String MethodName) {
for (Method method : clazz.getMethods())
{
MethodNode methodNode=new MethodNode(method,isMethod);
methodNode.setMethodName(MethodName);
if(method.isAnnotationPresent(Before.class))
{
if(!BeforeDelegatedSet.containsKey(key))
BeforeDelegatedSet.put(key,new ArrayList<>());
BeforeDelegatedSet.get(key).add(methodNode);
}
if(method.isAnnotationPresent(After.class))
{
if(!AfterDelegatedSet.containsKey(key))
AfterDelegatedSet.put(key,new ArrayList<>());
AfterDelegatedSet.get(key).add(methodNode);
}
}
}
然后在CreateBean的时候就要查找BeforeDelegatedSet,AfterDelegatedSet这两个set看是否有这个类的增强,如果有那么取出来放入设置放入动态工厂,当从动态工厂里面拿对象的时候将这些方法设置放入代理对象中
if(BeforeDelegatedSet.containsKey(beanDefintion.getClazz().getName()))
{
dynamicBeanFactory.setDelegated(true);
dynamicBeanFactory.setBeforemethodCache(BeforeDelegatedSet.get(beanDefintion.getClazz().getName()));
}
if(AfterDelegatedSet.containsKey(beanDefintion.getClazz().getName()))
{
dynamicBeanFactory.setDelegated(true);
dynamicBeanFactory.setAftermethodCache(AfterDelegatedSet.get(beanDefintion.getClazz().getName()));
}
//此方法用于返回是不是动态代理对象
public Object getTarget() {
if(isDelegated)
{
BeanProxyUtil beanProxyUtil=new BeanProxyUtil();
beanProxyUtil.setAftermethodCache(getAftermethodCache());
beanProxyUtil.setBeforemethodCache(getBeforemethodCache());
return beanProxyUtil.creatCarProxy(instance);
}else
return instance;
}
这样当执行的时候就循环遍历放入代理中的方法,如果是类的每个类级别的增强,类中的每个方法都要执行,如果是方法的(有个bool值isFuntion表明是方法上的增强)则只有某个特定的方法执行
package com.baoliang.spring.ProxyUtils;
import com.baoliang.spring.Helper.MethodNode;
import com.baoliang.spring.Helper.Container;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
public class BeanProxyUtil implements InvocationHandler {
private Object tartget;
private ArrayList<MethodNode> BeforemethodCache;
private ArrayList<MethodNode> AftermethodCache;
public ArrayList<MethodNode> getBeforemethodCache() {
return BeforemethodCache;
}
public void setBeforemethodCache(ArrayList<MethodNode> beforemethodCache) {
BeforemethodCache = beforemethodCache;
}
public ArrayList<MethodNode> getAftermethodCache() {
return AftermethodCache;
}
public void setAftermethodCache(ArrayList<MethodNode> aftermethodCache) {
AftermethodCache = aftermethodCache;
}
public Object creatCarProxy(Object target) {
this.tartget=target;
try {
Object proxy = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
return proxy;
}catch (Exception e)
{
e.printStackTrace();
}
return null;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
Object result=null;
//整个类级别的切面方法执行
if(BeforemethodCache!=null)
for(MethodNode beforMethod:BeforemethodCache)
{
if((!beforMethod.isFunction()))
{
String[] name=beforMethod.getMethod().getDeclaringClass().toString().split("\\.");
beforMethod.getMethod().invoke(Container.singletonObjects.get(name[name.length-1]));
}
}
//特定方法执行
if(BeforemethodCache!=null)
for(MethodNode beforMethod:BeforemethodCache)
{
if(beforMethod.isFunction()&&beforMethod.getMethodName().equals(method.getName()))
{
String[] name=beforMethod.getMethod().getDeclaringClass().toString().split("\\.");
beforMethod.getMethod().invoke(Container.singletonObjects.get(name[name.length-1]));
}
}
result=method.invoke(tartget,args);
if(AftermethodCache!=null)
for(MethodNode afterMethod:AftermethodCache)
{
if(afterMethod.isFunction()&&afterMethod.getMethodName().equals(method.getName()))
{
String[] name=afterMethod.getMethod().getDeclaringClass().toString().split("\\.");
afterMethod.getMethod().invoke(Container.singletonObjects.get(name[name.length-1]));
}
}
//类级别
if(AftermethodCache!=null)
for(MethodNode afterMethod:AftermethodCache)
{
if((!afterMethod.isFunction()))
{
String[] name=afterMethod.getMethod().getDeclaringClass().toString().split("\\.");
afterMethod.getMethod().invoke(Container.singletonObjects.get(name[name.length-1]));
}
}
return result;
}
}