手写简单Aop,展示aop设计思路和基础原理
提示:本文章适合有一定java反射基础的程序员,博主还是个新手新手超新手,欢迎指正!!!本文是参考Java 编程逻辑一书…
文章目录
Aop 简介:
简介百度一大堆,这里简单说下博主自己的理解,Aop其实就是用来解决成品系统中添加辅助功能的一种方式。当你的系统所有功能都完成了,你调试 的时候发现没有日志,调试很不方便时,你想添加日志功能上去,但是现在所有的 功能都已经做完。你给每个功能都添加日志时,就会有大量的工作,这种硬编码的方式太过笨重,于是就有人提出了aop的方式。它时通过动态代理为需要增强功能的类生成一个代理类,这个代理可以在功能方法执行前后执行额外的新增功能。同时它和之前的功能逻辑相分离,代码优雅。以松耦合的方式完成了功能的增强。Aop 主要应用于日志、性能监控、权限检查,数据库事务
提示:以下是本篇文章正文内容,下面案例可供参考
一、Aop 的基础原理是动态代理,动态代理又有哪些呢?
1. JDK 代理:
JDK代理面向的是一组接口,它为这些接口动态的创建了一个实现类 ,接口的具体实现逻辑是通过自定义的InvocationHandler实现的,也就是说其背后不一定有真正被代理的对象,也可能有多个实际对象,根据情况动态选择。
2. CGLIB 代理:
CGLIB 是第三方的类库。它面向的是一个具体的类。它动态的 创建了一个新类,继承了具体的类,重写了它的方法。Aop是有CGLIB来实现的。
二、手写Aop实例
1.创建自定义注解
代码如下(示例):
/**
* 切面注解
* @author 9699
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Aspect {
Class<?>[] values();
}
/**
* 依赖注解
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Inject {
}
/**
* 在xx之前执行注解
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Before {
}
/**
* 在xx执行之后注解
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface After {
}
/**
* 出现异常时标记注解
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Exception {
}
2.创建切面类
代码如下(示例):
package Proxy.MineExerciseAop;
import java.lang.reflect.Method;
/**
* 增加日志切面类
*/
@Aspect(values = {OrdinaryServiceA.class, OrdinaryServiceB.class})
public class InfixLogAspect {
@Before
public static void before(Object object, Method method,Object[] args){
if(method == null){
System.out.println("方法为空");
}
System.out.println("当前执行的类:"+method.getDeclaringClass().getSimpleName() +
"当前执行方法:" + method.getName());
}
@After
public static void after(Object object, Method method, Object[] args, Object result){
System.out.println("当前执行的类:"+method.getDeclaringClass().getSimpleName() +
"当前执行方法:" + method.getName());
}
}
/**
*异常切面增强类
*/
@Aspect(values = OrdinaryServiceB.class)
public class InfixExceptionAspect {
@Exception
public static void exception(Object object, Method method, Object [] args, Throwable e){
System.out.println("当前执行的类:"+method.getDeclaringClass().getSimpleName() +
"当前执行方法:" + method.getName());
}
}
3.创建功能类
代码如下(示例):
/**
* 功能类A
*/
public class OrdinaryServiceA {
@Inject
private OrdinaryServiceB ordinaryServiceB;
public OrdinaryServiceA() {
}
public void action(){
ordinaryServiceB.writeLog();
}
}
/**
* 功能类B
*/
public class OrdinaryServiceB {
public void writeLog(){
System.out.println("当前类的第一个方法: " + this.getClass().getMethods()[0].getName());
}
}
4.创建增强方法类型枚举
代码如下(示例):
/**
* 切面增强方法类型
*/
public enum InterceptPoint {
BEFORE,AFTER,EXCEPTION
}
5.创建核心容器类
代码如下(示例):
package Proxy.MineExerciseAop;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
/**
* DI容器,aop动态代理核心逻辑
*1.当调用静态方法getInstance(),会先加载静态属性和静态代码块,将切点方法添加到静态注册容器中
* 当生成cglib代理类后,调用方法时,会跳到动态代理方法intercept()方法中,执行实例对象目标方法
*/
public class MineCglibContainer {
//1.切点方法静态注册容器
static Map<Class<?>, Map<InterceptPoint, List<Method>>> interceptMethodsMap = new HashMap<>();
//1.切面类集合,本来是要扫描包下所有类,找到有切面注解的类在添加到该切面容器中,现在简化为直接手动添入
static List<Class<?>> aspects = new ArrayList<>(Arrays.asList(
new Class<?> []{InfixLogAspect.class, InfixExceptionAspect.class}));
//1.静态注入数据
static{
init();
}
//初始化数据
private static void init() {
for (Class<?> cls: aspects) {
Aspect aspect = cls.getAnnotation(Aspect.class);
if(aspect != null){
Class<?> [] interceptCls = aspect.values();
for (Class<?> incs: interceptCls) {
Method [] methods = cls.getDeclaredMethods();
for (Method method:methods) {
if(method.isAnnotationPresent(Before.class)){
addInterceptMethod(incs, InterceptPoint.BEFORE,method);
}else if(method.isAnnotationPresent(After.class)){
addInterceptMethod(incs, InterceptPoint.AFTER,method);
}else if(method.isAnnotationPresent(Exception.class)){
addInterceptMethod(incs, InterceptPoint.EXCEPTION,method);
}
}
}
}
}
}
//向容器添加切点方法数据
public static void addInterceptMethod(Class<?> cls,InterceptPoint point,Method method){
if(method == null){
return;
}
Map<InterceptPoint,List<Method>> map = interceptMethodsMap.get(cls);
if(map == null){
map = new HashMap<>();
interceptMethodsMap.put(cls,map);
}
List<Method> methodList = map.get(point);
if(methodList == null){
methodList = new ArrayList<>();
map.put(point,methodList);
}
methodList.add(method);
}
//CGLIB 动态代理逻辑
static class MineInterceptor implements MethodInterceptor{
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws InvocationTargetException, IllegalAccessException {
Object result = null;
//执行before注解方法
try {
List<Method> beforeMethods = getInterceptMethod(o.getClass().getSuperclass(), InterceptPoint.BEFORE);
for (Method me : beforeMethods) {
me.invoke(null, o, method, objects);
}
//执行目标方法
result = methodProxy.invokeSuper(o, objects);
//执行after注解方法
List<Method> afterMethods = getInterceptMethod(o.getClass().getSuperclass(), InterceptPoint.AFTER);
for (Method me : afterMethods) {
me.invoke(null, o, method, objects,result);
}
}catch (Throwable e){
e.printStackTrace();
List<Method> exceptionMethods = getInterceptMethod(o.getClass().getSuperclass(),InterceptPoint.EXCEPTION);
for (Method me: exceptionMethods) {
me.invoke(null,o,method,objects,e);
}
}
return result;
}
}
//获取静态切点方法容器中的方法
public static List<Method> getInterceptMethod(Class<?> cls, InterceptPoint point){
Map<InterceptPoint,List<Method>> map = interceptMethodsMap.get(cls);
if(map == null){
return Collections.emptyList();
}
List<Method> methods = map.get(point);
if(methods == null){
return Collections.emptyList();
}
return methods;
}
//获取对象,DI依赖
public static <T> T getInstance(Class<?> cls) throws IllegalAccessException, InstantiationException {
//生成对象
Object o = createInstance(cls);
//获取本类所有属性
Field [] fields = cls.getDeclaredFields();
for (Field field: fields) {
//判断是否有依赖注解
if(field.isAnnotationPresent(Inject.class)){
//判断属性是否有读写权限
if(!field.isAccessible()){
//给属性设置读写权限
field.setAccessible(true);
}
//获取属性类型
Class<?> fieldType = field.getType();
//设置属性值
field.set(o,getInstance(fieldType));
}
}
return (T)o;
}
//创建对象
public static <T> T createInstance(Class<?> cls) throws IllegalAccessException, InstantiationException {
if(!interceptMethodsMap.containsKey(cls)){
return (T) cls.newInstance();
}
//cglib 代理增强类,相当于jdk 代理的Proxy
Enhancer enhancer = new Enhancer();
//设置父类
enhancer.setSuperclass(cls);
//设置回调
enhancer.setCallback(new MineInterceptor());
//创建代理类对象
return (T) enhancer.create();
}
public static void main(String[] args) throws InstantiationException, IllegalAccessException {
OrdinaryServiceA proxyA = MineCglibContainer.getInstance(OrdinaryServiceA.class);
proxyA.action();
}
}
总结
这是博主写的第一篇文章,在大牛们面前献丑了!!希望大佬们多多指正,小菜我会再接再厉的。本文借鉴自java逻辑编程一书,这本书写的很不错,适合新手的进阶书籍。看了这本书,小菜java基础更上了一层楼,在这里推荐一下。