IOC

原文鏈接:https://blog.csdn.net/cuterabbitbaby/article/details/80559989

  1. IoC 是編程原則 - 不是特定的產(chǎn)品, 不是具體實(shí)現(xiàn)方式, 當(dāng)然也和具體編程語言無關(guān)

  2. 在傳統(tǒng)編程范式中, 程序調(diào)用可重用的庫

  3. 在 IoC 原則下, 程序接受通用框架的調(diào)用控制 - 框架調(diào)用程序代碼

  4. 與 IoC 原則相關(guān)的概念包括:

  5. IoC 的設(shè)計(jì)目的包括:

    • 將執(zhí)行任務(wù)和任務(wù)實(shí)現(xiàn)解耦

    • 讓模塊專注于設(shè)計(jì)任務(wù)

    • 模塊僅依賴于設(shè)計(jì)契約而無需關(guān)注其他系統(tǒng)如何工作

    • 避免模塊替換時(shí)的副作用

IOC和APO區(qū)別

簡單來講兩者一個(gè)是思想一個(gè)是原則牵舵,我們運(yùn)用AOP思想抽離東西之后,又運(yùn)用IOC原則添加其復(fù)用性,減少過度依賴俘枫。

AspectJ

IOC5.png

使用場景基于AOP的動(dòng)態(tài)權(quán)限管理囱晴、基于AOP的業(yè)務(wù)數(shù)據(jù)埋點(diǎn)箱季、基于AOP的性能監(jiān)測系統(tǒng)等等裸删。

配置中Gradle說明:http://www.reibang.com/p/c66f4e3113b3

使用說明:https://blog.csdn.net/innost/article/details/49387395

術(shù)語
  • Joinpoint(連接點(diǎn)) 所謂連接點(diǎn)是指那些被攔截到的點(diǎn)

  • Pointcut(切入點(diǎn)) 所謂切入點(diǎn)是指我們要對(duì)哪些 Joinpoint 進(jìn)行攔截的定義

  • Advice(通知/增強(qiáng)) 所謂通知是指攔截到 Joinpoint 之后所要做的事情就是通知

  • Introduction(引介) 引介是一種特殊的通知在不修改類代碼的前提下, Introduction 可以在運(yùn)行期為類 動(dòng)態(tài)地添加一些方法或 Field

  • Target(目標(biāo)對(duì)象) 代理的目標(biāo)對(duì)象

  • Weaving(織入) 是指把增強(qiáng)應(yīng)用到目標(biāo)對(duì)象來創(chuàng)建新的代理對(duì)象的過程. AspectJ 采用編譯期織入和類裝在期織入

  • Proxy(代理) 一個(gè)類被 AOP 織入增強(qiáng)后,就產(chǎn)生一個(gè)結(jié)果代理類

  • Aspect(切面) 是切入點(diǎn)和通知(引介)的結(jié)合

IOC1.png
Join Points 說明 示例
method call 函數(shù)調(diào)用 比如調(diào)用Log.e()换帜,這是一處JPoint
method execution 函數(shù)執(zhí)行 比如Log.e()的執(zhí)行內(nèi)部楔壤,是一處JPoint。注意它和method call的區(qū)別惯驼。method call是調(diào)用某個(gè)函數(shù)的地方蹲嚣。而execution是某個(gè)函數(shù)執(zhí)行的內(nèi)部。
constructor call 構(gòu)造函數(shù)調(diào)用 和method call類似
constructor execution 構(gòu)造函數(shù)執(zhí)行 和method execution類似
field get 獲取某個(gè)變量 比如讀取DemoActivity.debug成員
field set 設(shè)置某個(gè)變量 比如設(shè)置DemoActivity.debug成員
pre-initialization Object在構(gòu)造函數(shù)中做得一些工作祟牲。 很少使用
initialization Object 在構(gòu)造函數(shù)中做得工作 很少使用
static initialization 類初始化 比如類的static{}
handler 異常處理 比如try catch(xxx)中隙畜,對(duì)應(yīng)catch內(nèi)的執(zhí)行 advice execution 這個(gè)是AspectJ的內(nèi)容,稍后再說
advice execution 這個(gè)是AspectJ的內(nèi)容说贝,稍后再說
Advice分類(通知類型)
  • Before
    前置通知, 在目標(biāo)方法執(zhí)行之前執(zhí)行通知方法(應(yīng)用:各種校驗(yàn))

  • After
    后置通知, 目標(biāo)方法執(zhí)行后執(zhí)行通知方法(應(yīng)用:清理現(xiàn)場)

  • Around
    環(huán)繞通知, 在通知方法中執(zhí)行目標(biāo)方法執(zhí)行, 控制目標(biāo)方法執(zhí)行時(shí)機(jī), (應(yīng)用:十分強(qiáng)大议惰,可以做任何事情)

  • AfterReturning
    后置返回通知, 目標(biāo)方法正常返回返回后執(zhí)行通知,所以可以獲得方法的返回值乡恕。(應(yīng)用:常規(guī)數(shù)據(jù)處理)

  • AfterThrowing
    異常通知, 目標(biāo)方法執(zhí)行后拋出異常時(shí)執(zhí)行通知 (應(yīng)用:包裝異常信息)

切入點(diǎn)指示符

切入點(diǎn)表達(dá)式可以通過&&言询、||和俯萎!進(jìn)行組合,也可以通過名字引用切入點(diǎn)表達(dá)式
通過組合倍试,可以建立更加復(fù)雜的切入點(diǎn)表達(dá)式
1. 選擇特定類型的連接點(diǎn)讯屈,如:execution蛋哭,get县习,set,call谆趾,handler

ioc3.png

  • 下面是一個(gè)Method Signature的execution

    @Pointcut("execution(@com.dn_alan.myapplication.annotation.BehaviorTrace *  *(..))||withincode()")
    public void methodAnnottatedWithBehaviorTrace() {
      Log.d("alan","methodAnnottatedWithBehaviorTrace BehaviorTraceAspect");
    }
    

    完整的表達(dá)式:@注解 訪問權(quán)限 返回值的類型 包名.函數(shù)名(參數(shù))
    1. @注解和訪問權(quán)限(public/private/protect躁愿,以及static/final)屬于可選項(xiàng)。
    如果不設(shè)置它們沪蓬,則默認(rèn)都會(huì)選擇彤钟。以訪問權(quán)限為例,如果沒有設(shè)置訪問權(quán)限作為條件跷叉,那么public逸雹,private,protect及static云挟、final的函數(shù)都會(huì)進(jìn)行搜索梆砸。
    2. 返回值類型就是普通的函數(shù)的返回值類型。
    如果不限定類型的話园欣,就用通配符表示
    3. 包名.函數(shù)名用于查找匹配的函數(shù)帖世。
    可以使用通配符,包括*和..以及+號(hào)沸枯。其中*號(hào)用于匹配除.號(hào)之外的任意字符日矫,而..則表示任意子package,+號(hào)表示子類绑榴。
    比如:
    java.*.Date:可以表示java.sql.Date哪轿,也可以表示java.util.Date
    Test
    :可以表示T estBase,也可以表示TestDervied
    java..*:表示java任意子類
    java..*Model+:表示Java任意package中名字以Model結(jié)尾的子類翔怎,比如TabelModel缔逛,TreeModel

    4. 最后來看函數(shù)的參數(shù)。
    參數(shù)匹配比較簡單姓惑,主要是參數(shù)類型褐奴,比如:
    (int, char):表示參數(shù)只有兩個(gè),并且第一個(gè)參數(shù)類型是int于毙,第二個(gè)參數(shù)類型是char
    (String, ..):表示至少有一個(gè)參數(shù)敦冬。并且第一個(gè)參數(shù)類型是String,后面參數(shù)類型不限唯沮。在參數(shù)匹配中脖旱,
    ..代表任意參數(shù)個(gè)數(shù)和類型
    (Object ...):表示不定個(gè)數(shù)的參數(shù)堪遂,且類型都是Object,這里的...不是通配符萌庆,而是Java中代表不定參數(shù)的意思

  • Constructorsignature和Method Signature類似溶褪,只不過構(gòu)造函數(shù)沒有返回值,而且函數(shù)名必須叫new践险。
    比如:public *..TestDerived.new(..):

    1. public:選擇public訪問權(quán)限
      *..代表任意包名
    2. TestDerived.new:代表TestDerived的構(gòu)造函數(shù)
      (..):代表參數(shù)個(gè)數(shù)和類型都是任意
  • 再來看Field Signature和Type Signature猿妈,

    1. Field Signature標(biāo)準(zhǔn)格式:
      @注解 訪問權(quán)限 類型 類名.成員變量名
      其中,@注解和訪問權(quán)限是可選的
      類型:成員變量類型巍虫,代表任意類型
      類名.成員變量名:成員變量名可以是
      彭则,代表任意成員變量
      比如,
      set(inttest..TestBase.base):表示設(shè)置TestBase.base變量時(shí)的JPoint
    2. Type Signature:直接上例子
      staticinitialization(test..TestBase):表示TestBase類的static block
      handler(NullPointerException):表示catch到NullPointerException的JPoint占遥。

2:確定連接點(diǎn)的范圍俯抖,如:within,withincode

關(guān)鍵詞 說明 示例
within(TypePattern) TypePattern標(biāo)示package或者類瓦胎。TypePatter可以使用通配符 表示某個(gè)Package或者類中的所有JPoint芬萍。比如within(Test):Test類中(包括內(nèi)部類)所有JPoint。
withincode(Constructor Signature| Method Signature) 表示某個(gè)構(gòu)造函數(shù)或其他函數(shù)執(zhí)行過程中涉及到的JPoint 比如withinCode(* TestDerived.testMethod(..))表示testMethod涉及的JPoint,withinCode( *.Test.new(..))表示Test構(gòu)造函數(shù)涉及的JPoint
cflow(pointcuts) cflow是call flow的意思cflow的條件是一個(gè)pointcut 比如cflow(call TestDerived.testMethod):表示調(diào)用TestDerived.testMethod函數(shù)時(shí)所包含的JPoint搔啊,包括testMethod的call這個(gè)JPoint本身
cflowbelow(pointcuts) cflow是call flow的意思柬祠。 比如 cflowblow(call TestDerived.testMethod):表示調(diào)用TestDerived.testMethod函數(shù)時(shí)所包含的JPoint,不包括testMethod的call這個(gè)JPoint本身
this(Type) JPoint的this對(duì)象是Type類型坯癣。(其實(shí)就是判斷Type是不是某種類型瓶盛,即是否滿足instanceof Type的條件) JPoint是代碼段(不論是函數(shù),異常處理示罗,static block)惩猫,從語法上說,它都屬于一個(gè)類蚜点。如果這個(gè)類的類型是Type標(biāo)示的類型轧房,則和它相關(guān)的JPoint將全部被選中。 示例的testMethod是TestDerived類绍绘。所以 this(TestDerived)將會(huì)選中這個(gè)testMethod JPoint
target(Type) JPoint的target對(duì)象是Type類型 和this相對(duì)的是target奶镶。不過target一般用在call的情況。call一個(gè)函數(shù)陪拘,這個(gè)函數(shù)可能定義在其他類厂镇。比如testMethod是TestDerived類定義的。那么 target(TestDerived)就會(huì)搜索到調(diào)用testMethod的地方左刽。但是不包括testMethod的execution JPoint
args(TypeSignature) 用來對(duì)JPoint的參數(shù)進(jìn)行條件搜索的 比如args(int,..)捺信,表示第一個(gè)參數(shù)是int,后面參數(shù)個(gè)數(shù)和類型不限的JPoint欠痴。
  • within(com.itheima.aop..*)
  • this(com.itheima.aop.user.UserDAO)
  • target(com.itheima.aop.user.UserDAO)
  • args(int,int)
  • bean('userServiceId')
代碼

世界上沒有憑空調(diào)用迄靠,不管你是動(dòng)態(tài)代理或者注解或者AspectJ 都是有注入口存在秒咨。
APJ還對(duì)我們主動(dòng)調(diào)用的方法做增加,并在靜態(tài)代碼塊中做了初始化掌挚。我們調(diào)用這些有標(biāo)識(shí)符的方法雨席,它就會(huì)主動(dòng)調(diào)用我們的加了Aspect標(biāo)識(shí)的類中符合邏輯的方法,這樣我們就可以抽離出共性邏輯吠式,做一個(gè)單獨(dú)的模塊陡厘。

另外withincode這個(gè)標(biāo)識(shí)符有問題,省略缺少奇徒,各種寫法都嘗試了都不行雏亚,偶爾還爆空指針缨硝,從1.9降到1.8也不行摩钙,不知道網(wǎng)上的人是怎么寫出來了的。


IOC4.png
@Aspect
public class BehaviorTraceAspect {
    //定義切面的規(guī)則
    //1查辩、就再原來的應(yīng)用中那些注解的地方放到當(dāng)前切面進(jìn)行處理
    @Pointcut("execution(@com.example.apjdemo.annotation.BehaviorTrace *  *(..))"
//            + "&& args() "
//            + "&& args(android.view.View) "
//            + //"&& within(MainActivity)"
            +"&& !withincode(@com.example.apjdemo.annotation.BehaviorTrace void com.example.apjdemo.MainActivity.mAudio())"
            +"")
    public void methodAnnottatedWithBehaviorTrace() {
    }

    @Pointcut("execution(@com.example.apjdemo.annotation.BehaviorTrace *  *(..)) " +
            "&& methodAnnottatedWithBehaviorTrace() " +
            "&& !within(MainActivity)")
    public void all() {
    }

    //2胖笛、對(duì)進(jìn)入切面的內(nèi)容如何處理
    //@Before 在切入點(diǎn)之前運(yùn)行
//    @After("methodAnnottatedWithBehaviorTrace()")
    //@Around 在切入點(diǎn)前后都運(yùn)行
    @Around("methodAnnottatedWithBehaviorTrace()||all()")
    public Object weaveJoinPoint(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        String className = methodSignature.getDeclaringType().getSimpleName();
        String methodName = methodSignature.getName();
        String value = methodSignature.getMethod().getAnnotation(BehaviorTrace.class).value();

        long begin = System.currentTimeMillis();
        Object result = joinPoint.proceed();
        SystemClock.sleep(100);
        long duration = System.currentTimeMillis() - begin;
        Log.e("pp", String.format("%s功能:%s類的%s方法執(zhí)行了,用時(shí)%d ms",
                value, className, methodName, duration));
        return result;
    }
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface BehaviorTrace {
    String value();
}
@BehaviorTrace("語音消息")
public void mShake(View view) {
    Log.e("mShake","mShake");
}

//語音消息
public void mAudio(View view) {
    Log.e("mAudio","mAudio");
    mShake(view);
    kewudewithin();
}

//視頻通話
public void mVideo(View view) {
    Log.e("mVideo","mVideo");
    kewudewithincode();
}

public void kewudewithin(){
    Log.e("kewudewithin","kewudewithin");
    bumingsuoyi();
}

public void kewudewithincode() {
    Log.e("kewudewithincode","kewudewithincode");
    bumingsuoyi();
}
@BehaviorTrace("bumingsuoyi")
public void bumingsuoyi() {
}

當(dāng)期兩個(gè)項(xiàng)目對(duì)比下gradle配置

動(dòng)態(tài)代理

摘至作者:jxiang112http://www.reibang.com/p/85d181d7d09a

流程總結(jié):

校驗(yàn)代理類方法調(diào)用處理程序h不能為空
動(dòng)態(tài)生成代理類class文件格式字節(jié)流
通過loader加載創(chuàng)建代表代理類的class對(duì)象
根據(jù)代理類的構(gòu)造器創(chuàng)建代理類宜岛,
根據(jù)代理類接口先得到代理類的類全限名长踊、方法列表、異常列表通過ProxyClassFactory內(nèi)部調(diào)用了native層方法
返回動(dòng)態(tài)創(chuàng)建生成的代理類

  • Proxy.java
    static final 私有內(nèi)部類 ProxyClassFactory和KeyFactory

getProxyClass0,內(nèi)有判斷實(shí)現(xiàn)的接口數(shù)量不能超過65535就是Short類型的最大值

private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
        proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());

Proxy.newProxyInstance()->getProxyClass0(loader, intfs)
->proxyClassCache.get(loader, interfaces)->WeakCache.get(K key, P parameter)
  • WeakCache.java
    new KeyFactory(), new ProxyClassFactory() 一個(gè)是key的生成器扒寄,一個(gè)value的生成器
    Factory是WeakCache的final內(nèi)部類實(shí)現(xiàn)了Supplier接口
對(duì)象初始化時(shí)就會(huì)有個(gè)緩存map    
private final ConcurrentMap<Object, ConcurrentMap<Object, Supplier<V>>> map
        = new ConcurrentHashMap<>();

WeakCache.get()方法:
    supplier實(shí)際就是Factory
    獲取當(dāng)前key對(duì)應(yīng)的cacheKey的緩存supplier的map胖喳,如果沒有創(chuàng)建map并放入緩存map
    從緩存supplier的map中獲取supplier
    factory = null
    while循環(huán) {
         if (supplier != null) {
                // supplier might be a Factory or a CacheValue<V> instance
                V value = supplier.get();
                if (value != null) {
                    return value;
                }
         }
         如果factory = null
           factory = new Factory(key, parameter, subKey, valuesMap);
         如果supplier  = null
           把factory放入cacheKey對(duì)應(yīng)的緩存supplier的map
           supplier =  factory;
     }

Factory.get->value = Objects.requireNonNull(valueFactory.apply(key, parameter))->valueFactory構(gòu)造方法傳入 new ProxyClassFactory()->ProxyClassFactory.apply(ClassLoader loader, Class<?>[] interfaces)
  • ProxyClassFactory.java
    1. 根據(jù)代理類接口先得到代理類的類全限名雾狈、方法列表、異常列表
    2. 根據(jù)步驟1中的類全限名阱佛、方法列表、異常列表戴而、接口列表生成class文件格式的字節(jié)流凑术,其中方法的實(shí)現(xiàn)會(huì)最終調(diào)用InvoationHanlder的invoke方法
 @FastNative private static native Class<?> generateProxy(
     String name, Class<?>[] interfaces,ClassLoader loader, Method[] methods,                  Class<?>[][] exceptions);
  1. 使用類加載器加載步驟2中的字節(jié)流,創(chuàng)建生成動(dòng)態(tài)代理類對(duì)象
  2. 使用步驟3中創(chuàng)建生成的代理類對(duì)象
使用
IMy iMy = new MyImpl();
MyProxy myProxy = new MyProxy(iMy);
myProxy.ganni();

IMe iMe = new MeImpl();
MeProxy meProxy = new MeProxy(iMe);
meProxy.dani();

DynamicProxy dynamicProxy = new DynamicProxy(meProxy);
IMe iMeProxy = (IMe) Proxy.newProxyInstance(getClassLoader(), new Class[]{IMe.class}, dynamicProxy);
iMeProxy.dani();
DynamicProxy dynamicProxy2 = new DynamicProxy(myProxy);
IMy iMyProxy = (IMy) Proxy.newProxyInstance(getClassLoader(), new Class[]{IMy.class}, dynamicProxy2);
iMyProxy.ganni();

public interface IMe {
    String dani();
}

public interface IMy {
    String ganni();
}

public class MeImpl implements IMe {
    @Override
    public String dani() {
        return null;
    }
}

public class MeProxy implements IMe{

    private final IMe mIme;

    public MeProxy(IMe iMe) {
        mIme = iMe;
    }

    @Override
    public String dani() {
        da110();
        return mIme.dani();
    }

    private void da110(){
        Log.e("MeProxy","woda110");
    }
}

public class MyImpl implements IMy {
    @Override
    public String ganni() {
        return "laiba";
    }
}

public class MyProxy implements IMy {

    private final IMy mIMy;

    public MyProxy(IMy iMy) {
        mIMy = iMy;
    }

    @Override
    public String ganni() {
        da110();
        return mIMy.ganni();
    }

    private void da110(){
        Log.e("MyProxy","woda110");
    }
}

public class DynamicProxy implements InvocationHandler {

    private final Object mobject;

    public DynamicProxy(Object object) {
        mobject = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Log.e("MyProxy",proxy.getClass().getName());
        Log.e("MyProxy",mobject.getClass().getName());

        return method.invoke(mobject,args);
    }

    private void da110(){
        Log.e("MyProxy","wotisuoyouren da110");
    }
}

AutoService

利用@AutoService(IFunction.class)通過ServiceLoader.load(IFunction::class.java)找到所有實(shí)現(xiàn)類

有人說可以用來打包http://www.reibang.com/p/a94e6a32f10f

這里主要介紹@AutoService(Processor.class)就是APT

APT&&Javapoet

中間還加如了javapoet

  • 注解處理Moduel

    /**
     * 這個(gè)類就是APT
     */
    @AutoService(Processor.class)
    public class MyAnotationCompile extends AbstractProcessor {
     //1.定義一個(gè)用于生成文件的對(duì)象
     Filer filer;
    
     @Override
     public synchronized void init(ProcessingEnvironment processingEnvironment) {
         super.init(processingEnvironment);
         filer = processingEnvironment.getFiler();
     }
    
     //2.需要確定當(dāng)前APT處理所有模塊中哪些注解
     //可以用注解標(biāo)識(shí)@SupportedAnnotationTypes()
     @Override
     public Set<String> getSupportedAnnotationTypes() {
         Set<String> set = new HashSet<>();
         set.add(MyAnntation.class.getCanonicalName());
         return set;
     }
    
     //3.支持的JDK的版本
     //沒有會(huì)報(bào)錯(cuò)
     @Override
     public SourceVersion getSupportedSourceVersion() {
         return SourceVersion.latestSupported();
     }
    
     /**
      * 在這個(gè)方法中所意,我們?nèi)ド蓪?shí)現(xiàn)類
      * @param set
      * @param roundEnvironment
      * @return
      */
     @Override
    public boolean process(Set<? extends TypeElement> set, 
                           RoundEnvironment roundEnvironment) {
    
         Set<? extends Element> elementsAnnotatedWith = roundEnvironment.getElementsAnnotatedWith(MyAnntation.class);
         Map<String, List<VariableElement>> map = new HashMap<>();
    
         for (Element element : elementsAnnotatedWith) {
             VariableElement variableElement = (VariableElement) element;
             String activityName = variableElement.getEnclosingElement().getSimpleName().toString();
             List<VariableElement> elementList = map.get(activityName);
             if (elementList == null) {
                 elementList = new ArrayList<>();
                 map.put(activityName, elementList);
             }
             elementList.add(variableElement);
         }
    
         if (map.size() > 0) {
             Writer writer = null;
             Iterator<String> iterator = map.keySet().iterator();
             Writer writer1 = null;
             while (iterator.hasNext()) {
                 String activityName = iterator.next();
                 List<VariableElement> elementList = map.get(activityName);
    
                 TypeElement enclosingElement = (TypeElement) elementList.get(0).getEnclosingElement();
                 String packageName = processingEnv.getElementUtils().getPackageOf(enclosingElement).toString();
    
                 for (VariableElement variableElement : elementList) {
                     String variableName = variableElement.getSimpleName().toString();
                     String name = variableElement.getAnnotation(MyAnntation.class).value();
    //                    try {
    //                        JavaFileObject classFile = filer.createSourceFile(packageName+"." + name);
    //                        writer1 = classFile.openWriter();
    //                        writer1.write("package "+packageName+"." + name);
    //                    } catch (IOException e) {
    //                        e.printStackTrace();
    //                    } finally {
    //                        try {
    //                            writer1.close();
    //                        } catch (IOException e) {
    //                            e.printStackTrace();
    //                        }
    //                    }
                     MethodSpec main = MethodSpec.methodBuilder("main")
                             .addModifiers(Modifier.PUBLIC, Modifier.STATIC)
                             .returns(void.class)
                             .addParameter(String[].class, "args")
                             .addStatement("$T.out.println($S)", System.class, "Hello, JavaPoet!")
                             .build();
    
                     TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")
                             .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
                             .addMethod(main)
                             .build();
    
                     JavaFile javaFile = JavaFile.builder(packageName+"." + name, helloWorld)
                             .build();
                     try {
                         javaFile.writeTo(filer);
                     } catch (IOException e) {
                         e.printStackTrace();
                     } finally {
                     }
                 }
             }
         }
         return true;
    
    //        //獲取控件的名字
    //        String variableName=variableElement.getSimpleName().toString();
    //        //獲取ID
    //        int id=variableElement.getAnnotation(BindView.class).value();
    //        //獲取控件的類型
    //        TypeMirror typeMirror=variableElement.asType();
    //        如果APT過程中生成的類也需要進(jìn)行注解處理的話則需要返回false淮逊,方便再一次執(zhí)行。
    //        上層是 processImpl方法
       }
    }
    
    implementation project(path: ':libannotation')
    
    implementation "com.squareup:javapoet:1.11.1"
    annotationProcessor'com.google.auto.service:auto-service:1.0-rc4'
    compileOnly'com.google.auto.service:auto-service:1.0-rc4'
    
  • 注解module(libannotation):

    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.SOURCE)
    public @interface MyAnntation {
     String value();
    }
    
  • appmodule:

    public class MainActivity extends AppCompatActivity {
       @MyAnntation("nihaoa")
       View view;
     
       @Override
       protected void onCreate(Bundle savedInstanceState) {
           super.onCreate(savedInstanceState);
           setContentView(R.layout.activity_main);
       }
    }
    
    implementation project(path: ':libannotation')
    implementation "com.squareup:javapoet:1.11.1"
    annotationProcessor project(path: ':libanotationcompile')
    
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末扶踊,一起剝皮案震驚了整個(gè)濱河市泄鹏,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌秧耗,老刑警劉巖备籽,帶你破解...
    沈念sama閱讀 216,402評(píng)論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異绣版,居然都是意外死亡胶台,警方通過查閱死者的電腦和手機(jī)歼疮,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來诈唬,“玉大人韩脏,你說我怎么就攤上這事≈酰” “怎么了赡矢?”我有些...
    開封第一講書人閱讀 162,483評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長阅仔。 經(jīng)常有香客問我吹散,道長,這世上最難降的妖魔是什么八酒? 我笑而不...
    開封第一講書人閱讀 58,165評(píng)論 1 292
  • 正文 為了忘掉前任空民,我火速辦了婚禮,結(jié)果婚禮上羞迷,老公的妹妹穿的比我還像新娘界轩。我一直安慰自己,他們只是感情好衔瓮,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評(píng)論 6 388
  • 文/花漫 我一把揭開白布浊猾。 她就那樣靜靜地躺著,像睡著了一般热鞍。 火紅的嫁衣襯著肌膚如雪葫慎。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,146評(píng)論 1 297
  • 那天薇宠,我揣著相機(jī)與錄音偷办,去河邊找鬼。 笑死昼接,一個(gè)胖子當(dāng)著我的面吹牛爽篷,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播慢睡,決...
    沈念sama閱讀 40,032評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼逐工,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了漂辐?” 一聲冷哼從身側(cè)響起泪喊,我...
    開封第一講書人閱讀 38,896評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎髓涯,沒想到半個(gè)月后袒啼,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,311評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評(píng)論 2 332
  • 正文 我和宋清朗相戀三年蚓再,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了滑肉。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,696評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡摘仅,死狀恐怖靶庙,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情娃属,我是刑警寧澤六荒,帶...
    沈念sama閱讀 35,413評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站矾端,受9級(jí)特大地震影響掏击,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜秩铆,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評(píng)論 3 325
  • 文/蒙蒙 一砚亭、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧豺旬,春花似錦钠惩、人聲如沸柒凉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽膝捞。三九已至坦刀,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蔬咬,已是汗流浹背鲤遥。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留林艘,地道東北人盖奈。 一個(gè)月前我還...
    沈念sama閱讀 47,698評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像狐援,于是被迫代替她去往敵國和親钢坦。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評(píng)論 2 353