springaop之拙劣实现(基于注解配置的aop)
简单使用
1.定义注解
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyLog {
}
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyLog2 {
}
2.业务类
@Service
public class ARoleService2 {
public ARoleService2(){
System.out.println("正在创建ARoleService2");
}
//可以多个注解修饰同一个方法
@MyLog2
@MyLog
public List<String> getNameList(String... name){
List<String> list = new ArrayList<>();
for (String s : name) {
list.add(s);
}
return list;
}
}
3.aop增强方法
@Component
@EabelMyAop
public class MySpringAop {
private static final Logger log = LoggerFactory.getLogger(MySpringAop.class);
public MySpringAop() {
log.info("正在创建MySpringAop对象");
}
/**
* @param joinPoint
*/
@MyBefore(pointCut = MyLog.class)
public Object Around(MyJoinPoint joinPoint) throws Throwable {
String methodName = joinPoint.getSignature().getMethodName();
Object[] args = joinPoint.getArgs();
log.info("\r\n方法名称:{}\r\n方法参数:{}",methodName,JSON.toJSONString(args));
return null;
}
@MyAfter(pointCut = MyLog.class)
public Object after(MyJoinPoint joinPoint) throws Throwable {
String methodName = joinPoint.getSignature().getMethodName();
Object result = joinPoint.getResult();
log.info("\r\n后置方法方法名称:{}\r\n返回结果:{}",methodName,JSON.toJSONString(result));
return result;
}
@MyAround(pointCut = MyLog2.class,order = 8)
public Object Around2(AroundJointPoint joinPoint) throws Throwable {
String methodName = joinPoint.getSignature().getMethodName();
Object[] args = joinPoint.getArgs();
log.info("============环绕通知log2,执行前============");
Object proceed = joinPoint.proceed();
log.info("============环绕通知log2,执行后============");
return proceed;
}
@MyAround(pointCut = MyLog.class,order = 2)
public Object Around3(AroundJointPoint joinPoint) throws Throwable {
log.info("============环绕通知log1,执行前============");
Object proceed = joinPoint.proceed();
log.info("============环绕通知log1,执行后============");
return proceed;
}
@MyAfterThrowing(pointCut = MyLog.class)
public Object after(AroundJointPoint joinPoint) throws Throwable {
return "发生cuowu 信息";
}
}
4.测试
@SpringBootTest(classes = MaAopRun.class)
public class MyAopTest {
@Autowired
private ARoleService2 aRoleService2;
@Test
public void tsst1(){
List<String> nameList = aRoleService2.getNameList("张三", "李四", "王五");
System.out.println(nameList);
}
}
//运行结果
正在创建ARoleService2
2020-06-15 18:25:20.516 INFO 1020 --- [ main] com.git.proxy.ProxyUtil : 正在为com.git.maaop.test.service.RoleService创建cgLib动态代理对象
2020-06-15 18:25:20.578 INFO 1020 --- [ main] com.git.myaop.MyAopTest : Started MyAopTest in 1.1 seconds (JVM running for 2.492)
2020-06-15 18:25:20.915 INFO 1020 --- [ main] com.git.maaop.test.config.MySpringAop :
方法名称:getNameList
方法参数:[["张三","李四","王五"]]
2020-06-15 18:25:20.915 INFO 1020 --- [ main] com.git.maaop.test.config.MySpringAop : ============环绕通知log1,执行前============
2020-06-15 18:25:20.915 INFO 1020 --- [ main] com.git.maaop.test.config.MySpringAop : ============环绕通知log2,执行前============
2020-06-15 18:25:20.926 INFO 1020 --- [ main] com.git.maaop.test.config.MySpringAop : ============环绕通知log2,执行后============
2020-06-15 18:25:20.927 INFO 1020 --- [ main] com.git.maaop.test.config.MySpringAop : ============环绕通知log1,执行后============
2020-06-15 18:25:20.927 INFO 1020 --- [ main] com.git.maaop.test.config.MySpringAop :
后置方法方法名称:getNameList
返回结果:["张三","李四","王五"]
[张三, 李四, 王五]
实现原理
必须对spring的后置处理器和cglib代理有所了解,不然看了也白看
实现思路
1.在spring启动过程中使用beanFactoryPostProcessor对所有的BeanDefinition扫描,将bean里面的所有加了@MyAround的方法存到一个list里面(包括before和after等)
2.利用beanPostProcessor在bean初始化的时候判断该bean要不要被增强,如果需要的话返回一个代理对象(cglib)
- 为什么会在初始化的时候返回代理对象(因为在实例化的时候返回对象,后面就不会初始化了),但是这么做会创建两次bean(一次spring调用的,一次cglib创建子类的时候自动的
- 至于bean的创建顺序问题,可以通过beanFactory来获取,如果没有spring会自动创建
原理
1.aop
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
//通过import一个类实现开启自定义aop的作用
@Import(MyAopProcessor.class)
public @interface EabelMyAop {
}
2.MyAopProcessor
/**
* MyAopProcessor实现了
* 1.BeanFactoryPostProcessor beanFactoryPostProcessor后置处理器用于筛选那些那些方法上面加了自定义注解,比如MyAround等
* 2.InstantiationAwareBeanPostProcessor 用于在初始化方法之后返回一个代理对象,本文采用cglib代理
* 3.BeanFactoryAware 为了获得beanFactory的功能
* @author authorZhao
* @date 2020年06月06日
*/
public class MyAopProcessor implements BeanFactoryPostProcessor,InstantiationAwareBeanPostProcessor, BeanFactoryAware {
private static final Logger log = LoggerFactory.getLogger(MyAopProcessor.class);
static {//开启cglib生成的代理clazz输出到文件
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "./");
}
/**
* 中间商的方法
*/
private Map<Method,Class> methodClassHashMap = new HashMap<>();
private BeanFactory beanFactory;
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();
Arrays.stream(beanDefinitionNames).forEach(n->{
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(n);
String beanClassName = beanDefinition.getBeanClassName();
if(StringUtils.isEmpty(beanClassName))return;
try {
Class beanClass = Class.forName(beanClassName);
Arrays.stream(beanClass.getDeclaredMethods()).forEach(i->{
if(i.isAnnotationPresent(MyAround.class)||i.isAnnotationPresent(MyBefore.class)||i.isAnnotationPresent(MyAfter.class)||i.isAnnotationPresent(MyAfterThrowing.class))
//注解校验
methodClassHashMap.put(i,beanClass);
});
} catch (Exception e) {
log.error(beanClassName);
}
});
AopUtil.setMap(methodClassHashMap);
}
/**
* 在初始化之前返回一个对象,关于为什么不在这一步返回代理对象是因为还想再后面继续初始化的操作
* @param beanClass
* @param beanName
* @return
* @throws BeansException
*/
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
return null;
}
/**
* 初始化之前执行的方法,因为要初始化,所以在这一步不做操作
* @param bean
* @param beanName
* @return
* @throws BeansException
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
/**
* 初始化之后的操作,这一步返回代理对象,本文采用cglib代理
* @param bean
* @param beanName
* @return
* @throws BeansException
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
//.构建MyJoinPoint,cglib多重代理问题会有方法冲突的问题
//1.判断该对象需不需要被代理
List<PointChain> pointChainList = AopUtil.getPointChainList(methodClassHashMap, bean.getClass(), beanFactory);
if(ListUtil.isEmpety(pointChainList))return bean;
AopMethodProxy aopMethodProxy = new AopMethodProxy(pointChainList);
//2.生成代理对象
Object object = ProxyUtil.getObject(bean.getClass(),aopMethodProxy);
//3.属性赋值,之前的对象就没用了
BeanUtils.copyProperties(bean,object);
return object;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
}
3.cglib代理的实现
思路,遍历执行before方法、around方法、after方法,抛异常就会执行afterThrow
@Override
public Object apply(Object proxy, Method method, Object[] params, MethodProxy methodProxy) throws Throwable {
cglibJoinPoint.clear();
cglibJoinPoint.setArgs(params);
cglibJoinPoint.setProxy(proxy);
cglibJoinPoint.setMethodProxy(methodProxy);
Object result = null;
try {
//1.不需要增强的方法直接返回
if (!AopUtil.needEnhance(method)) return methodProxy.invokeSuper(proxy, params);
//构建方法
//2.before方法
beforePointChains.forEach(i->{
MyJoinPoint myJoinPoint = i.getMyJoinPoint();
((MyJoinPointAbstract) myJoinPoint).setArgs(params);
i.intercept();
});
//3.around方法
cglibJoinPoint.setArgs(params);
//((AbstractPointChain) i).setParams(new Object[]{myJoinPoint});
result = cglibJoinPoint.proceed();
//4.after方法
for (AfterPointChain afterPointChain : afterPointChains) {
MyJoinPointAbstract myJoinPoint = ((MyJoinPointAbstract) afterPointChain.getMyJoinPoint());
myJoinPoint.setArgs(params);
myJoinPoint.setResult(result);
if (((AbstractPointChain) afterPointChain).hasReturn()) {
return afterPointChain.intercept();
}else{
afterPointChain.intercept();
}
}
//5.afterThrowing
}catch (Throwable e){
cglibJoinPoint.setError(e);
for (AfterThrowPointChain afterThrowPointChain : afterThrowPointChains) {
if (((AbstractPointChain) afterThrowPointChain).hasReturn()) {
return afterThrowPointChain.intercept();
}else{
afterThrowPointChain.intercept();
}
}
}
cglibJoinPoint.restIndex();
return result;
}
本文的难点在于执行arond方法,我这里所有方法都只有一个固定的参数joinPoint,执行
proceed方法就是执行目标方法,之前想到了多个around的时候采用多重代理,但是结果cglib的多重代理报错(查看字节码反编译发现是生成了重复的方法),所以采用这种责任链模式,在所有得方法里面的joinPoint其实是一个对象
public Object Around3(AroundJointPoint joinPoint) throws Throwable {
log.info("============环绕通知log1,执行前============");
Object proceed = joinPoint.proceed();
log.info("============环绕通知log1,执行后============");
return proceed;
}
所有的方法都是遍历pointChain来执行
PointChain接口以及实现
public interface PointChain {
/**
* 执行方法
* @return
*/
Object intercept();
/**
* 序号,序号越小越优先执行
* @return
*/
default int getOrder(){
return 0;
}
/**
* 获取切入点函数
* @return
*/
MyJoinPoint getMyJoinPoint();
}
一个具体的jointChain,AroundPointChain
/**
* @author authorZhao
* @date 2020年06月09日
*/
public interface AroundPointChain extends PointChain{
/**
* 执行方法,默认执行各自的方法
* @return
*/
@Override
default Object intercept() {
return doAround();
}
/**
* 在原始方法前后执行
* @return
*/
Object doAround();
}
AroundPointChainImpl
public class AroundPointChainImpl extends AbstractPointChain implements AroundPointChain {
public AroundPointChainImpl(Object obj, Method method, Object[] params) {
super(obj, method, params);
}
public AroundPointChainImpl() {
}
@Override
public Object doAround(){
try{
return getMethod().invoke(getObj(),getParams());
}catch (Throwable e){
throw new MyAopException(e);
}
}
}
AbstractPointChain
pointChain继承的抽象类,这个类用于执行加了@MyAround注解方法
public abstract class AbstractPointChain {
/**
* aop配置的对象
*/
private Object obj;
/**
* aop处的方法
*/
private Method method;
/**
* 参数
*/
private Object[] params;
/**
* 固定参数参数
*/
private MyJoinPoint myJoinPoint;
private MySignature mySignature;
private int order=0;
public AbstractPointChain(Object obj, Method method, Object[] params) {
this.obj = obj;
this.method = method;
this.params = params;
}
public AbstractPointChain() {
}
/**
* 方法是否返回结果
* @return
*/
public boolean hasReturn(){
Class<?> returnType = method.getReturnType();
if(returnType==Void.class)return false;
return true;
}
public Object getObj() {
return obj;
}
public void setObj(Object obj) {
this.obj = obj;
}
public Method getMethod() {
return method;
}
public void setMethod(Method method) {
this.method = method;
}
public Object[] getParams() {
//return params;
return new Object[]{getMyJoinPoint()};
}
public void setParams(Object[] params) {
this.params = params;
}
public MyJoinPoint getMyJoinPoint() {
return myJoinPoint;
}
public void setMyJoinPoint(MyJoinPoint myJoinPoint) {
this.myJoinPoint = myJoinPoint;
}
public MySignature getMySignature() {
return mySignature;
}
public void setMySignature(MySignature mySignature) {
this.mySignature = mySignature;
}
public int getOrder() {
return order;
}
public void setOrder(int order) {
this.order = order;
}
}
每个pointchain里面都有同个joinPoint,这个jointPoint的构建是关键,jointPoint既能执行原始方法,又能执行环绕通知里面的其他通知方法。
JoinPoint实现
/**
* @author authorZhao
* @date 2020年06月06日
*/
public interface MyJoinPoint {
/**
* 获取当前对象,增强之后的对象,暂时不对外开放
* @return
*/
default Object getThis(){
return null;
};
/**
* 获取目标对象,可以在任何阶段获得,暂时不对外开放
* @return
*/
default Object getTarget(){
return null;
};
/**
* 获取方法的参数,可以任意阶段获取
* @return
*/
Object[] getArgs();
/**
* 获得返回结果,只有在后置方法里面能够获得
* @return 获得返回结果
*/
Object getResult();
/**
* 获得方法签名
* @return 暂时返回签名对象
*/
MySignature getSignature();
}
/**
* 环绕方法
* @author authorZhao
* @since 2020-06-14
*/
public interface AroundJointPoint extends MyJoinPoint{
/**
* 执行目标方法,如果有多重代理会执行下一层代理方法,
* 直到所有代理执行完毕会执行目标方法
* @return Object
* @throws Throwable
*/
Object proceed() throws Throwable;
/**
* 执行原始方法,这样子会导致多重拦截失效
* @return
* @throws Throwable
*/
Object invoke()throws Throwable;
}
public abstract class MyJoinPointAbstract implements AroundJointPoint, ErrorJointPoint {
/**
* 参数
*/
private Object[] args;
/**
* 返回结果
*/
private Object result;
/**
* 异常信息
*/
private Throwable error;
private MySignature signature;
public MyJoinPointAbstract(Object[] args) {
this.args = args;
}
public MyJoinPointAbstract() {
}
@Override
public Object[] getArgs() {
return args;
}
public void setArgs(Object[] args) {
this.args = args;
}
@Override
public Object getResult() {
return result;
}
public void setResult(Object result) {
this.result = result;
}
@Override
public Throwable getError() {
return error;
}
public void setError(Throwable error) {
this.error = error;
}
@Override
public MySignature getSignature() {
return signature;
}
public void setSignature(MySignature signature) {
this.signature = signature;
}
}
GglibJoinPoint是具体的类,里面包含了cglib的MethodProxy,目前这里实现了功能,但是比较拙劣
/**
* @author authorZhao
* @date 2020年06月06日
*/
public class GglibJoinPoint extends MyJoinPointAbstract {
//private AroundPointChain aroundPointChain;
private Map<Integer,AroundPointChain> pointChainMap = new HashMap<>();
/**
* cglib的代理对象
*/
private Object proxy;
/**
* cglib的代理方法
*/
private MethodProxy methodProxy;
private int index = 0;
public GglibJoinPoint() {
}
public GglibJoinPoint(Object[] args, AroundPointChain aroundPointChain, Object proxy, MethodProxy methodProxy) {
super(args);
this.proxy = proxy;
this.methodProxy = methodProxy;
}
public GglibJoinPoint(AroundPointChain aroundPointChain, Object proxy, MethodProxy methodProxy) {
this.proxy = proxy;
this.methodProxy = methodProxy;
}
public GglibJoinPoint(Map<Integer, AroundPointChain> pointChainMap) {
this.pointChainMap = pointChainMap;
}
/**
* 每个方法执行该方法应该是执行PointChain的方法,当PointChain全部执行完毕才执行原始的方法
* @return
* @throws InvocationTargetException
* @throws IllegalAccessException
*/
@Override
public Object proceed() throws Throwable {
Object obj;
if(ListUtil.isEmpety(pointChainMap)) {
obj = invoke();
setResult(obj);
return obj;
}
int size = pointChainMap.size();
if(index>=size){
obj = invoke();
setResult(obj);
return obj;
}else{
index++;
obj = pointChainMap.get(index-1).intercept();
}
setResult(obj);
return obj;
}
public static Map<Integer,AroundPointChain> build(List<AroundPointChain> aroundPointChainList){
if(ListUtil.isEmpety(aroundPointChainList))return null;
Map<Integer,AroundPointChain> map = new HashMap<>();
for (int i = 0; i < aroundPointChainList.size(); i++) {
map.put(i,aroundPointChainList.get(i));
}
return map;
}
public static GglibJoinPoint buildJointPoint(List<AroundPointChain> aroundPointChainList){
return new GglibJoinPoint(build(aroundPointChainList));
}
public void initMap(List<AroundPointChain> aroundPointChainList){
this.pointChainMap=build(aroundPointChainList);
}
/**
* 清空属性,重复利用
*/
public void clear(){
/*setArgs(null);
setError(null);
setResult(null);
setProxy(null);
setMethodProxy(null);*/
}
@Override
public Object invoke() throws Throwable{
return this.methodProxy.invokeSuper(this.proxy,getArgs());
}
public Object getProxy() {
return proxy;
}
public void setProxy(Object proxy) {
this.proxy = proxy;
}
public MethodProxy getMethodProxy() {
return methodProxy;
}
public void setMethodProxy(MethodProxy methodProxy) {
this.methodProxy = methodProxy;
}
public void restIndex(){
this.index=0;
}
}
代码上多了自己也越看越乱,再次详细用文字描述一下。
- pointchain就是加了@MyAround注解的方法
- jopintPoint就是里面的参数,但是他可以执行目标方法。
- 如果只有一个环绕通知目标方法就是业务代码里面的,如果有多个通知目标方法就是下一个通知的方法
具体实现细节有兴趣的可参考我的github拙劣实现springaop
完
1.非spring环境直接aspectj
2.个人分享,篇幅较长,有兴趣的看github实现
3.本人原创,转载请申明