Cglib底层是如何生成字节码文件的
ASM
对于需要手动操纵字节码的需求,可以使用ASM,它可以直接生产 .class字节码文件,也可以在类被加载入JVM之前动态修改类行为。ASM的应用场景有AOP(Cglib就是基于ASM)、热部署、修改其他jar包中的类等。
整体的操作流程图如下所示:
先通过ClassReader读取编译好的.class文件
其通过访问者模式(Visitor)对字节码进行修改,常见的Visitor类有:对方法进行修改的MethodVisitor,或者对变量进行修改的FieldVisitor等
通过ClassWriter重新构建编译修改后的字节码文件、或者将修改后的字节码文件输出到文件中
如何自己实现一个简单版本的AOP
首先需要定义相关的注解:
package org.idea.spring.aop.version1.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * @Author linhao * @Date created in 3:49 下午 2021/5/6 */ @Retention(value = RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Pointcut { String value() default ""; }
package org.idea.spring.aop.version1.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * @Author linhao * @Date created in 3:42 下午 2021/5/6 */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Before { String value(); }
package org.idea.spring.aop.version1.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * @Author linhao * @Date created in 3:43 下午 2021/5/6 */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface After { String value(); }
package org.idea.spring.aop.version1.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * @Author linhao * @Date created in 3:41 下午 2021/5/6 */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface Aspect { String value() default ""; }
接下来为自己定义的这些注解添砖加瓦,组合使用到一个Aspect的切面当中去:
package org.idea.spring.aop.version1.aspect; import org.idea.spring.aop.version1.annotation.After; import org.idea.spring.aop.version1.annotation.Aspect; import org.idea.spring.aop.version1.annotation.Before; import org.idea.spring.aop.version1.annotation.Pointcut; import java.lang.reflect.Method; /** * 切面 * * @Author linhao * @Date created in 3:43 下午 2021/5/6 */ @Aspect public class MyAspect { @Pointcut("org.idea.spring.aop.version1.test.*.*(..)") public void pointCut(){ } @Before("pointCut()") public void doBefore(Method method, Object object){ System.out.println("doBefore"); } @After("pointCut()") public void doAfter(Method method, Object object){ System.out.println("doAfter"); } }
同时补充一个测试使用的方法
package org.idea.spring.aop.version1.test; /** * @Author linhao * @Date created in 3:44 下午 2021/5/6 */ public class TestMethod { public void doTest(){ System.out.println("do test"); } }
最后是一个核型的AspectLoader加载器代码
package org.idea.spring.aop.version1; import com.google.common.collect.ImmutableSet; import com.google.common.reflect.ClassPath; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import org.idea.spring.aop.version1.annotation.After; import org.idea.spring.aop.version1.annotation.Aspect; import org.idea.spring.aop.version1.annotation.Before; import org.idea.spring.aop.version1.annotation.Pointcut; import org.idea.spring.aop.version1.test.TestMethod; import java.io.IOException; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * @Author linhao * @Date created in 3:51 下午 2021/5/6 */ public class AspectLoader { /** * 配置扫描aop的aspect基础包路径 */ public static final String PACKAGE_NAME = "org.idea.spring.aop"; /** * 模拟ioc容器 */ public Map<String, Object> beanContainer = new HashMap<>(); public AspectLoader() { this.beanContainer.put("TestMethod", new TestMethod()); } public static void main(String[] args) { AspectLoader aspectLoader = new AspectLoader(); aspectLoader.init(); TestMethod testMethod = (TestMethod) aspectLoader.beanContainer.get("TestMethod"); testMethod.doTest(); } /** * 初始化aop的配置相关 */ private void init() { try { //获取切面点aspect List<Class> targetsWithAspectJAnnotationList = this.getAspectClass(); for (Class targetsWithAspectJAnnotation : targetsWithAspectJAnnotationList) { Method beforeMethod = this.getBeforeMethod(targetsWithAspectJAnnotation); Pointcut pointcut = (Pointcut) this.getMethodAnnotation(targetsWithAspectJAnnotation, Pointcut.class); Method afterMethod = this.getAfterMethod(targetsWithAspectJAnnotation); List<Class> classList = this.getClassFromPackage(AspectLoader.class, pointcut.value().substring(0, pointcut.value().indexOf("*") - 1)); for (Class sourceClass : classList) { Object aspectObject = targetsWithAspectJAnnotation.newInstance(); Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(sourceClass); enhancer.setCallback(new MethodInterceptor() { @Override public Object intercept(Object obj, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { beforeMethod.invoke(aspectObject, method, obj); methodProxy.invokeSuper(obj, objects); afterMethod.invoke(aspectObject,method,obj); return obj; } }); Object proxyObj = enhancer.create(); this.beanContainer.put(sourceClass.getSimpleName(), proxyObj); } } } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } } private List<Class> getAspectClass() throws ClassNotFoundException, IOException { final ClassPath classPath = ClassPath.from(AspectLoader.class.getClassLoader()); List<Class> aspectClass = new ArrayList<>(); ImmutableSet<ClassPath.ClassInfo> clazz = classPath.getAllClasses(); List<ClassPath.ClassInfo> list = clazz.asList(); for (ClassPath.ClassInfo classInfo : list) { if (classInfo.getName() != null && classInfo.getPackageName().contains(PACKAGE_NAME)) { Class clazzTemp = Class.forName(classInfo.getName()); if (clazzTemp.isAnnotationPresent(Aspect.class)) { aspectClass.add(clazzTemp); } } } return aspectClass; } /** * 获取指定包名下边的所有类 * * @param source * @param packageName * @return * @throws Exception */ private List<Class> getClassFromPackage(Class source, String packageName) { List<Class> classList = new ArrayList<>(); final ClassPath classPath; try { classPath = ClassPath.from(source.getClassLoader()); ImmutableSet<ClassPath.ClassInfo> clazz = classPath.getAllClasses(); List<ClassPath.ClassInfo> list = clazz.asList(); for (ClassPath.ClassInfo classInfo : list) { if (classInfo.getName() != null && classInfo.getPackageName().contains(packageName)) { classList.add(Class.forName(classInfo.getName())); } } } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); } return classList; } private Annotation getMethodAnnotation(Class source, Class annotationClass) { Method[] methods = source.getDeclaredMethods(); for (Method method : methods) { if (method.isAnnotationPresent(annotationClass)) { Annotation[] beforeArr = method.getAnnotationsByType(annotationClass); if (beforeArr.length > 0) { return beforeArr[0]; } } } return null; } private Method getBeforeMethod(Class source) { Method[] methods = source.getDeclaredMethods(); for (Method method : methods) { if (method.isAnnotationPresent(Before.class)) { return method; } } return null; } private Method getAfterMethod(Class source) { Method[] methods = source.getDeclaredMethods(); for (Method method : methods) { if (method.isAnnotationPresent(After.class)) { return method; } } return null; } }
本文相关代码地址:
https://gitee.com/IdeaHome_admin/spring-framework-learn/tree/master/spring-aop