Aspject加载时织入示例
问题场景
最近的一个使用DDD风格建模的项目中,遇到这样的一个场景:
- 领域类的抽象类层次,作为Hibernate实体类使用,由于其包含了一些业务逻辑,需要Spring依赖注入的支持,故使用了@Configurable注解+AspectJ编译时织入的方式
- 具体领域类,一般没有业务逻辑,但是类数量较多,故使用Javassist进行自动的类生成
运行的时候出现问题了,使用Javassist生成的具体领域类,无法注入依赖,尽管其父类上有@Configurable注解。经过跟踪,发现子类也必须进行织入才能正常的进行依赖注入,那么,如何在生成字节码的时候,同时织入AOP逻辑呢?
AspectJ字节码织入工具类
其实AspectJ已经提供了加载时织入的API,下面这个工具类,即可用于织入任何指定的切面:| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 | import java.lang.instrument.IllegalClassFormatException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.aspectj.weaver.loadtime.Aj; import org.aspectj.weaver.loadtime.DefaultWeavingContext; import org.aspectj.weaver.loadtime.definition.Definition; import org.aspectj.weaver.tools.WeavingAdaptor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /**  * Weave byte codes at load time.  *   * @author Andrica Silviu  * @author WangZhen  */ public class AspectJBytecodeWeaver {     private static final Logger LOGGER = LoggerFactory.getLogger( AspectJBytecodeWeaver.class );     private class DynamicAspectWeavingContext extends DefaultWeavingContext     {         public DynamicAspectWeavingContext( ClassLoader loader )         {             super( loader );         }         public List<Definition> getDefinitions( ClassLoader loader, WeavingAdaptor adaptor )         {             List<Definition> definitions = new ArrayList<Definition>();             Definition d = new Definition();             for ( String aspectName : aspectNames )             {                 d.getAspectClassNames().add( aspectName );             }             d.appendWeaverOptions( "-Xjoinpoints:synchronization" );             if ( LOGGER.isDebugEnabled() )             {                 d.appendWeaverOptions( "-showWeaveInfo" );             }             definitions.add( d );             return definitions;         }     }     private final Map<ClassLoader, Aj> mapFromClassLoaderToAj;     private final String[]             aspectNames;     public AspectJBytecodeWeaver( String[] aspectName )     {         mapFromClassLoaderToAj = new ConcurrentHashMap<ClassLoader, Aj>();         this.aspectNames = aspectName;     }     /**      * Weaving delegation      *       * @param loader      *            the defining class loader      * @param className      *            the name of class beeing loaded      * @param bytes      *            the bytecode before weaving      * @return the weaved bytecode      */     public byte[] weave( ClassLoader loader, String className, byte[] bytes ) throws IllegalClassFormatException     {         if ( className.replace( "/", "." ).equals( aspectNames ) )         {             return null;         }         Aj aj = getAj( loader );         if ( LOGGER.isDebugEnabled() )         {             LOGGER.debug( "Weaving class : {} with aspect(s) :{}", className, Arrays.deepToString( aspectNames ) );         }         byte[] b = aj.preProcess( className, bytes, loader );         return b;     }     private Aj getAj( ClassLoader loader )     {         if ( mapFromClassLoaderToAj.containsKey( loader ) )         {             return mapFromClassLoaderToAj.get( loader );         }         Aj aj = new Aj( new DynamicAspectWeavingContext( loader ) );         mapFromClassLoaderToAj.put( loader, aj );         return aj;     } } | 
该工具类的一个实例,专门用于织入Spring aspects:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | public class SpringAspectJ {     private static final String               ASPECT_BEAN_CONFIG =                                                                          "org.springframework.beans.factory.aspectj.AnnotationBeanConfigurerAspect";     private static final String               ASPECT_SCHEDULING  =                                                                          "org.springframework.scheduling.aspectj.AnnotationAsyncExecutionAspect";     private static final String               ASPECT_TRANSACTION =                                                                          "org.springframework.transaction.aspectj.AnnotationTransactionAspect";     private static final String               ASPECT_CACHE       =                                                                          "org.springframework.cache.aspectj.AnnotationCacheAspect";     public static final AspectJBytecodeWeaver WEAVER             = new AspectJBytecodeWeaver( new String[] {                                                                  ASPECT_BEAN_CONFIG, ASPECT_SCHEDULING,                                                                  ASPECT_TRANSACTION, ASPECT_CACHE } ); } | 
在生成字节码时织入Spring-aspects
下面的例子中,首先生成了类的基本骨架,然后调用AspectJBytecodeWeaver进行织入。| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | ClassPool cp = ClassPool.getDefault(); ClassPath clsPath = new ClassClassPath( this.getClass() ); cp.insertClassPath( clsPath ); CtClass cc = cp.makeClass( getClassName() ); if ( StringUtils.isNotBlank( getSuperClassName() ) ) {     cc.setSuperclass( cp.get( getSuperClassName() ) ); } ClassFile cf = cc.getClassFile(); ConstPool constPool = cf.getConstPool(); if ( isWeaveSpringAspects() ) {     ClassLoader loader = Thread.currentThread().getContextClassLoader();     try     {         //织入Spring切面         byte[] b = SpringAspectJ.WEAVER.weave( loader, getClassName(), cc.toBytecode() );         cc.detach();         cc = cp.makeClass( new ByteArrayInputStream( b ) );     }     catch ( IOException e )     {         throw new RuntimeException( e.getMessage(), e );     } } Class<?> c = cc.toClass(); cc.detach(); return c; | 
 
            
Leave a Reply