AspectJ 编译
AspectJ 编译是通过AJC (AspectJ Complier) 编译工具编译Aspect代码,Android 项目中引入AspectJ 需要设置AJC 相关编译参数才能编译。
- l AspectJ比较强大,除了支持对source文件(即aj文件、或@AspectJ注解的Java文件,或普通java文件)直接进行编译外,
- l 还能对Java字节码(即对class文件)进行处理。有感兴趣的同学可以对aspectj-test小例子的class文件进行反编译,你会发现AspectJ无非是在被选中的JPoint的地方加一些hook函数。当然Before就是在调用JPoint之前加,After就是在JPoint返回之前加。
- l 更高级的做法是当class文件被加载到虚拟机后,由虚拟机根据AOP的规则进行hook。
以下对第二种使用方式进行说明
一、在需要添加的Module 中的build.gradle中添加gradle脚本
1、新建aopconfig.gradle 文件
import org.aspectj.bridge.IMessage
import org.aspectj.bridge.MessageHandler
import org.aspectj.tools.ajc.Main
buildscript {
repositories {
jcenter()
google()
}
dependencies {
classpath 'org.aspectj:aspectjtools:1.8.9'
}
}
final def log = project.logger
final def variants = project.android.applicationVariants
variants.all { variant ->
if (!variant.buildType.isDebuggable()) {
log.debug("Skipping non-debuggable build type '${variant.buildType.name}'.")
return
}
JavaCompile javaCompile = variant.javaCompile
javaCompile.doLast {
String[] args = ["-showWeaveInfo",
"-1.5",
"-inpath", javaCompile.destinationDir.toString(),
"-aspectpath", javaCompile.classpath.asPath,
"-d", javaCompile.destinationDir.toString(),
"-classpath", javaCompile.classpath.asPath,
"-bootclasspath", project.android.bootClasspath.join(File.pathSeparator)]
log.debug "ajc args: " + Arrays.toString(args)
MessageHandler handler = new MessageHandler(true)
new Main().run(args, handler)
for (IMessage message : handler.getMessages(null, true)) {
switch (message.getKind()) {
case IMessage.ABORT:
case IMessage.ERROR:
case IMessage.FAIL:
log.error message.message, message.thrown
break
case IMessage.WARNING:
log.warn message.message, message.thrown
break
case IMessage.INFO:
log.info message.message, message.thrown
break
case IMessage.DEBUG:
log.debug message.message, message.thrown
break
}
}
}
}
dependencies {
implementation 'org.aspectj:aspectjrt:1.8.9'
}
2、在app 中的build.gradle 中引入aopconfig.gradle,整个配置完成
apply from : "aopconfig.gradle"
二、使用Gradle Plugin设置编译参数
- 自定义Gradle Plugin
- 在apply 方法中实现参数设置
import com.android.build.gradle.LibraryPlugin
import org.aspectj.bridge.IMessage
import org.aspectj.bridge.MessageHandler
import org.aspectj.tools.ajc.Main
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.tasks.compile.JavaCompile
public class AopPlugin implements Plugin {
@Override
void apply(Project project) {
//判断应用此Module的Target类型是AppPlugin还是LibraryPlugin
def hasApp = project.plugins.withType(AppPlugin)
def hasLibrary = project.plugins.withType(LibraryPlugin)
if (!hasApp && !hasLibrary) {
throw new IllegalStateException("'android' or 'android-library' plugin required.")
}
final def log = project.logger
final def variants
if (hasApp) {
variants = project.android.applicationVariants
} else {
variants = project.android.libraryVariants
}
//添加依赖
project.dependencies {
compile 'org.aspectj:aspectjrt:1.8.9'
}
variants.all { variant ->
JavaCompile javaCompile = variant.javaCompile
javaCompile.doLast {
String[] args = [
"-showWeaveInfo",
"-1.5",
"-inpath", javaCompile.destinationDir.toString(),
"-aspectpath", javaCompile.classpath.asPath,
"-d", javaCompile.destinationDir.toString(),
"-classpath", javaCompile.classpath.asPath,
"-bootclasspath", project.android.bootClasspath.join(File.pathSeparator)
]
log.debug "ajc args:" + Arrays.toString(args)
printf("Aspectj compiler args :" + Arrays.toString(args))
MessageHandler handler = new MessageHandler(true);
new Main().run(args, handler);
for (IMessage message : handler.getMessages(null, true)) {
switch (message.getKind()) {
case IMessage.ABORT:
case IMessage.ERROR:
case IMessage.FAIL:
log.error message.message, message.thrown
break;
case IMessage.WARNING:
log.warn message.message, message.thrown
break;
case IMessage.INFO:
log.info message.message, message.thrown
break;
case IMessage.DEBUG:
log.info message.message, message.thrown
break;
}
}
}
}
}
}
参数说明:
参数 |
说明 |
-showWeaveInfo |
输入AJC 编译信息 |
-1.5 |
声明AJC 支持AspectJ 1.5 版本 |
-inpath |
需要编译的.class 文件目录(包含Jar文件) |
-classpath |
指定哪里可以找到用户的class 文件 |
-aspectpath |
aspect 编译的Jar文件或者目录路径 |
-d |
编译后输出的目录 |
-bootclasspath |
编译时修改本地的bootcloasspath |
其它参考:
https://eclipse.org/aspectj/doc/released/devguide/ajc-ref.html
AspectJ-specific options:
-inpath use classes in dirs and jars/zips in as source
( uses platform-specific path delimiter)
-injars use classes in zip files as source
( uses classpath delimiter)
deprecated - use inpath instead.
-aspectpath weave aspects in .class files from dirs and jars/zip into sources
( uses classpath delimiter)
-outjar put output classes in zip file
-outxml generate META-INF/aop.xml
-outxmlfile specify alternate destination output of -outxml
-argfile specify line-delimited list of source files
-showWeaveInfo display information about weaving
-incremental continuously-running compiler, needs -sourceroots
(reads stdin: enter to recompile and 'q' to quit)
-sourceroots compile all .aj and .java files in
( uses classpath delimiter)
-crossrefs generate .ajsym file into the output directory
-emacssym generate .ajesym symbol files for emacs support
-Xlint same as '-Xlint:warning'
-Xlint: set default level for crosscutting messages
( may be ignore, warning, or error)
-Xlintfile specify properties file to set per-message levels
(cf org/aspectj/weaver/XlintDefault.properties)
-X print help on non-standard options
Standard Eclipse compiler options:
Options enabled by default are prefixed with '+'
Classpath options:
-cp -classpath
specify location for application classes and sources
-bootclasspath
specify location for system classes
-d
destination directory (if omitted, no directory is created)
-d none generate no .class files
-encoding specify custom encoding for all sources. Each file/directory can override it
when suffixed with '['']' (e.g. X.java[utf8])
Compliance options:
-1.3 use 1.3 compliance level (implicit -source 1.3 -target 1.1)
-1.4 + use 1.4 compliance level
-1.5 -5 -5.0 use 1.5 compliance (-source 1.5 -target 1.5)
-1.6 -6 -6.0 use 1.6 compliance (-source 1.6 -target 1.6)
-1.7 -7 -7.0 use 1.7 compliance (-source 1.7 -target 1.7)
-1.8 -8 -8.0 use 1.8 compliance (-source 1.8 -target 1.8)
-source set source level: 1.3 to 1.8 (or 5, 5.0, etc)
-target set classfile target: 1.1 to 1.8 (or 5, 5.0, etc)
Warning options:
-deprecation + deprecation outside deprecated code
-nowarn -warn:none disable all warnings
-warn: enable exactly the listed warnings
-warn:+ enable additional warnings
-warn:- disable specific warnings
allDeadCode dead code including trivial if(DEBUG) check
allDeprecation deprecation including inside deprecated code
allJavadoc invalid or missing javadoc
allOver-ann all missing @Override annotations
all-static-method all method can be declared as static warnings
assertIdentifier + 'assert' used as identifier
boxing autoboxing conversion
charConcat + char[] in String concat
compareIdentical + comparing identical expressions
conditionAssign possible accidental boolean assignment
constructorName + method with constructor name
deadCode + dead code excluding trivial if (DEBUG) check
dep-ann missing @Deprecated annotation
deprecation + deprecation outside deprecated code
discouraged + use of types matching a discouraged access rule
emptyBlock undocumented empty block
enumIdentifier 'enum' used as identifier
enumSwitch incomplete enum switch
fallthrough possible fall-through case
fieldHiding field hiding another variable
finalBound type parameter with final bound
finally + finally block not completing normally
forbidden + use of types matching a forbidden access rule
hashCode missing hashCode() method when overriding equals()
hiding macro for fieldHiding, localHiding, typeHiding and
maskedCatchBlock
includeAssertNull raise null warnings for variables
that got tainted in an assert expression
indirectStatic indirect reference to static member
intfAnnotation + annotation type used as super interface
intfNonInherited + interface non-inherited method compatibility
intfRedundant find redundant superinterfaces
javadoc invalid javadoc
localHiding local variable hiding another variable
maskedCatchBlock + hidden catch block
nls string literal lacking non-nls tag //$NON-NLS-$
noEffectAssign + assignment without effect
null potential missing or redundant null check
nullDereference + missing null check
over-ann missing @Override annotation (superclass)
paramAssign assignment to a parameter
pkgDefaultMethod + attempt to override package-default method
raw + usage of raw type
semicolon unnecessary semicolon, empty statement
serial + missing serialVersionUID
specialParamHiding constructor or setter parameter hiding a field
static-method method can be declared as static
static-access macro for indirectStatic and staticReceiver
staticReceiver + non-static reference to static member
super overriding a method without making a super invocation
suppress + enable @SuppressWarnings
When used with -err:, it can also silent optional
errors and warnings
syncOverride missing synchronized in synchr. method override
syntheticAccess synthetic access for innerclass
tasks() tasks identified by tags inside comments
typeHiding + type parameter hiding another type
unavoidableGenericProblems + ignore unavoidable type safety problems
due to raw APIs
unchecked + unchecked type operation
unnecessaryElse unnecessary else clause
unqualifiedField unqualified reference to field
unused macro for unusedAllocation, unusedArgument,
unusedImport, unusedLabel, unusedLocal,
unusedPrivate, unusedThrown, and unusedTypeArgs
unusedAllocation allocating an object that is not used
unusedArgument unread method parameter
unusedImport + unused import declaration
unusedLabel + unused label
unusedLocal + unread local variable
unusedPrivate + unused private member declaration
unusedThrown unused declared thrown exception
unusedTypeArgs + unused type arguments for method and constructor
uselessTypeCheck unnecessary cast/instanceof operation
varargsCast + varargs argument need explicit cast
warningToken + unsupported or unnecessary @SuppressWarnings
AspectJ Api 相关核心类
org.aspectj.lang.annotation
包含了AspectJ 使用的注解
org.aspectj.lang
JoinPoint:表示切入点,带有切入点的相关信息
ProceedingJoinPoint: JoinPoint 子类,提供执行切入点源代码的能力,只能与Advice 的Around 配合使用。
Signature: PointCut 签名信息。
org.aspectj.lang.reflect
包含JoinPoint 具体的Signature接口类
org.aspectj.runtime.reflect
包含JoinPoint 具体的Signature接口类的实现类
org.aspectj.tools.ajbrowser
AspectJ 搜索核心了
org.aspectj.tools.ajc
Main: AspectJ AJC 入口