源码地址: https://download.csdn.net/download/dreams_deng/12239703
1.Aop实现方式: 动态代理、AspetJ
1. 加载期间 类加载 动态代理
2. 编译时 apt、操作字节码
javac aspecj(编辑器)修改.class
java -----> .class ---------------------> .class修改注入
aspectJ 在 Javac编译 以后 读取 .class 文件 使用apectJ 进行 替换
1.1. 静态代理案例:
静态代理:
被代理类和代理类同时实现相应的一套接口
动态代理:
在程序运行时候动态的创建代理类,
我要买房子...买手机... 动态创建买房子、买手机代理类....
package com.atguigu.java1;
//静态代理模式
//接口
interface ClothFactory{
void productCloth();
}
//被代理类
class NikeClothFactory implements ClothFactory{
@Override
public void productCloth() {
System.out.println("Nike工厂生产一批衣服");
}
}
//代理类
class ProxyFactory implements ClothFactory{
ClothFactory cf;
//创建代理类的对象时,实际传入一个被代理类的对象
public ProxyFactory(ClothFactory cf){
this.cf = cf;
}
@Override
public void productCloth() {
System.out.println("代理类开始执行,收代理费$1000");
cf.productCloth();
}
}
public class TestClothProduct {
public static void main(String[] args) {
NikeClothFactory nike = new NikeClothFactory();//创建被代理类的对象
ProxyFactory proxy = new ProxyFactory(nike);//创建代理类的对象
proxy.productCloth();
}
}
1.2. 动态代理 :
package com.atguigu.java1;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//动态代理的使用,体会反射是动态语言的关键
interface Subject {
void action();
}
// 被代理类
// 2. 第二部:被代理类实现
class RealSubject implements Subject {
public void action() {
System.out.println("我是被代理类,记得要执行我哦!么么~~");
}
}
class EatSubject implements Subject{
@Override
public void action() {
System.out.println("我要吃饭");
}
}
class DrinkWaterSubject implements Subject{
@Override
public void action() {
System.out.println("我要喝水.....我还要喝水.....");
}
}
// 1. 第一步, 这是系统封装好的 InvoacationHandler
class MyInvocationHandler implements InvocationHandler {
Object obj;// 实现了接口的被代理类的对象的声明
// ①给被代理的对象实例化②返回一个代理类的对象
public Object blind(Object obj) {
this.obj = obj;
// 这里返回一个代理类对象,参数意义
// 1. obj.getClass().getClassLoader() 表示代理类使用和被代理类同样的类加载器
// 2. obj.getClass().getInterfaces() 表示返回代理类对象实现了和被代理类对象同样的接口
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj
.getClass().getInterfaces(), this);
}
//当通过代理类的对象发起对被重写的方法的调用时,都会转换为对如下的invoke方法的调用
// methond.invoke调用被代理类的方法
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//method方法的返回值时returnVal
HumanUtils humanUtils=new HumanUtils();
humanUtils.method1();
Object returnVal = method.invoke(obj, args);
humanUtils.method2();
return returnVal;
}
}
class HumanUtils{
public void method1(){
System.out.println("我是method----1");
}
public void method2(){
System.out.println("我是method----2");
}
}
public class TestProxy {
public static void main(String[] args) {
//1.被代理类的对象
RealSubject real = new RealSubject();
//2.创建一个实现了InvacationHandler接口的类的对象
MyInvocationHandler handler = new MyInvocationHandler();
//3.调用blind()方法,动态的返回一个同样实现了real所在类实现的接口Subject的代理类的对象。
Object obj = handler.blind(real);
Subject sub = (Subject)obj;//此时sub就是代理类的对象
sub.action();//转到对InvacationHandler接口的实现类的invoke()方法的调用
//再举一例
NikeClothFactory nike = new NikeClothFactory();
ClothFactory proxyCloth = (ClothFactory)handler.blind(nike);//proxyCloth即为代理类的对象
proxyCloth.productCloth();
// 3. 具体调用
EatSubject eatSubject=new EatSubject();
Subject sub1= (Subject) handler.blind(eatSubject);
sub1.action();
DrinkWaterSubject drinkWater=new DrinkWaterSubject();
Subject drinksubjectinterface= (Subject) handler.blind(drinkWater);
drinksubjectinterface.action();
}
}
2. AspectJ 使用流程:
例子:子线程切换
1. 添加依赖
compile 'com.android.support:design:24.2.1'
compile 'io.reactivex.rxjava2:rxandroid:2.0.2'
2. 配置aspectJ, 在gradle中 android {} 同级别目录
import org.aspectj.tools.ajc.Main
//配置aspectJ
// aspectJ 在 Javac编译 以后 读取 .class 文件 使用apectJ 进行 替换
android.applicationVariants.all{
//编译Java代码的任务
JavaCompile javaCompile = it.javaCompile
// javac 执行以后 --doLast
javaCompile.doLast {
// println "在编译之后执行"
//执行 aspectJ 修改字节码的操作
String[] args = [
// 指定jdk
"-1.8",
// aspectJ 处理的源文件,aspectJ处理的源文件是.class,这个目录就是Java编译后的app\build\intermediates\classes\debug
"-inpath",javaCompile.destinationDir.toString(),
// aspectJ 处理完成以后输出的目录
"-d",javaCompile.destinationDir.toString(),
"-aspectpath",javaCompile.classpath.asPath,
"-classpath",javaCompile.classpath.asPath,
"-bootclasspath",project.android.bootClasspath.join(File.pathSeparator)
]
// 调用aspectJ编译器
new Main().runMain(args,false)
}
}
3. 自定义注解 @Async
package com.denganzhi.myappliction;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Created by Administrator on 2018\10\12 0012.
*/
// 什么时间去操作注解,注解的生命周期
// source 源码级别,在编译时候丢弃
// RetentionPolicty.class表示该注解在编译编译时期使用,在运行期间丢弃,不能获取
// RetentionPolicty.RUNTIME 表示该注解在运行期使用,可以通过放射获取
// @target表示该注解使用在方法上
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.METHOD)
// 修饰属性、方法、........
public @interface Async {
}
4. 定义切面
@Pointcut -->doAsync() 指定切入点
@Around("doAsync()") 切入点代码对应逻辑
@Aspect
public class AsyncAspect {
/* @around:围绕方法执行,就是需要自己调用方法
@before: 在方法执行之前执行
@after: 在方法执行之后执行
*
*/
@Pointcut("execution(@com.denganzhi.myappliction.Async void *(..))")
public void doAsync(){
}
// RXJava实现切换子线
// @Around("doAsync()")
// public void doAsyncMethod(final ProceedingJoinPoint joinPoint){
// //切换线程
// Completable.create(new CompletableOnSubscribe() {
// @Override
// public void subscribe(CompletableEmitter emitter) throws Exception {
// //子线程
// //执行原来的方法
// try{
// joinPoint.proceed();
// }catch (Throwable throwable){
// throwable.printStackTrace();
// }
// }
// }).subscribeOn(Schedulers.io()).subscribe();
//
// }
// 直接使用AspectJ
@Around("doAsync()")
public void doAsyncMethod(final ProceedingJoinPoint joinPoint){
new Thread(){
@Override
public void run(){
try{
joinPoint.proceed();
}catch (Throwable throwable){
throwable.printStackTrace();
}
}
}.start();
}
}
5. 使用注解
public class MainActivity extends Activity {
Button btn1;
@MyAnnotation(value = "xiaohei",name = "小明")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn1 = (Button)findViewById(R.id.btn1);
btn1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
readFile();
// 切面的真实应用
}
});
}
@Async
public void readFile(){
Log.e("denganzhi1","读取文件:"+Thread.currentThread().toString());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
showResult("小明","xiaohei");
}
}
3. 其他标签使用
@AfterReturning: 在函数返回值以后调用切入点函数
@AfterThrowing: 在函数抛出异常以后调用切入点函数
@Around: 手动调用 函数在切入点
1. 定义注解 @Main
package com.denganzhi.myappliction;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Created by Administrator on 2018\10\12 0012.
*/
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.METHOD)
public @interface Main {
}
2. 定义切面
@Aspect
public class MainAspect {
static Handler mhandler=new Handler(Looper.getMainLooper());
@Pointcut("execution(@com.denganzhi.myappliction.Main * *(..))")
public void doMain(){
}
// 直接在标签中注解,不使用 @Pointcut
@AfterThrowing(value = "execution(public int com.denganzhi.myappliction.ShowHello.showMessage(int,int))"
,throwing = "ex")
public void doHelloException(final ProceedingJoinPoint joinPoint, Exception ex){
Log.e("denganzhi1","异常是---------》"+ex);
}
@AfterReturning(value = "execution(public int com.denganzhi.myappliction.ShowHello.showMessage(int,int))"
,returning = "result")
public void doHelloException(final ProceedingJoinPoint joinPoint, Object result){
Log.e("denganzhi1","返回值是:---------》"+result);
}
@Around("execution(public int com.denganzhi.myappliction.ShowHello.showMessage(int,int))")
public Object doHello(final ProceedingJoinPoint joinPoint){
Object result=null;
try {
// 参数
// Object[] args= joinPoint.getArgs();
// 返回值
String methodName= joinPoint.getSignature().getName();
result= joinPoint.proceed();
List<Object> args= Arrays.asList(joinPoint.getArgs());
// String str= Arrays.toString(args);
Log.e("denganzhi1","methodName:"+methodName+" 返回值是:"+result+" args:"+args);
} catch (Throwable throwable) {
//throwable.printStackTrace();
Log.e("denganzhi1","异常通知:"+throwable.getMessage());
// throw new RuntimeException(throwable);
}
return result;
}
//RXJava
/* @Around("doMain()")
public void doMainMethod(final ProceedingJoinPoint joinPoint){
//保证在主线程
if(Looper.myLooper()==Looper.getMainLooper()){
try {
joinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return;
}
//如果不在 切换到主线程
Completable.create(new CompletableOnSubscribe() {
@Override
public void subscribe(CompletableEmitter emitter) throws Exception {
try{
joinPoint.proceed();
}catch (Throwable throwable){
throwable.printStackTrace();
}
}
}).subscribeOn(AndroidSchedulers.mainThread()).subscribe();
}*/
/* @around:围绕方法执行,就是需要自己调用方法
@before: 在方法执行之前执行
@after: 在方法执行之后执行
*/
// 异常通知,在执行方法抛出异常以后
// @AfterThrowing(value = "execution(@com.denganzhi.myappliction.Main * *(..))",
// throwing = "ex")
// public void doMainMethodAfter(final ProceedingJoinPoint joinPoint,final Exception ex){
// }
// 返回值通知,在执行方法返回值以后,获取方法返回值
// @AfterReturning(value = "execution(@com.denganzhi.myappliction.Main * *(..))",
// returning = "result")
// public void doMainMethodAfter(final ProceedingJoinPoint joinPoint,final Object result){
// }
// 指定切入点
@Around("doMain()")
public void doMainMethod(final ProceedingJoinPoint joinPoint){
//保证在主线程
if(Looper.myLooper()==Looper.getMainLooper()){
try {
joinPoint.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return;
}
Log.e("denganzhi1","来到这里没有");
mhandler.post(new Runnable() {
@Override
public void run() {
try {
// 参数
Object[] args= joinPoint.getArgs();
// 返回值
Object result= joinPoint.proceed();
String str= Arrays.toString(args);
Log.e("denganzhi1","参数是:"+str+"返回值是:"+result);
} catch (Throwable throwable) {
throwable.printStackTrace();
}
}
});
}
}
3. 使用注解标签
public class MainActivity extends Activity {
@MyAnnotation(value = "xiaohei",name = "小明")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Main
public void showResult(String arg1,String arg2){
Log.e("denganzhi1","写入文件:"+Thread.currentThread().toString());
Toast.makeText(MainActivity.this,"更新UI", Toast.LENGTH_LONG).show();
}
}