AOP-02
4.问题提出
在上一篇的MyProxyProvider类中,我们的输出语句功能比较弱,在实际开发中,我们希望是以一个方法的形式,嵌入到真正执行的目标方法前,怎么办?
1.使用土方法解决
需求分析:使用土方法解决前面的问题,后面使用spring的aop组件完成
改进MyProxyProvider:
主要是对前置/返回/异常/最终通知的代码进行封装,封装到不同的方法中进行调用。
package com.li.aop.proxy3;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
/**
* @author 李
* @version 1.0
* 返回一个动态代理对象,可以执行被代理的对象的方法
*/
public class MyProxyProvider {
//定义要执行的目标对象,该对象需要实现 SmartAnimal接口
private SmartAnimal target_animal;
//构造器
public MyProxyProvider(SmartAnimal target_animal) {
this.target_animal = target_animal;
}
//定义一个方法,在目标对象执行前执行
public void before(Method method, Object[] args) {
System.out.println("before-方法执行开始-日志-方法名-" + method.getName() +
"-参数 " + Arrays.toString(args));//AOP的角度看,是一个横切关注点-前置通知
}
//定义一个方法,在目标对象执行后行
public void after(Method method, Object result) {
System.out.println("after-方法执行正常结束-日志-方法名-" + method.getName()
+ "-结果 result = " + result);//也是一个横切关注点-返回通知
}
//定义方法返回代理对象,该代理对象可以执行目标对象
public SmartAnimal getProxy() {
//(1)先得到类加载器对象
ClassLoader classLoader = target_animal.getClass().getClassLoader();
//(2)得到要执行的目标对象的接口信息
Class<?>[] interfaces = target_animal.getClass().getInterfaces();
//(3)使用匿名内部类 创建 InvocationHandler对象
InvocationHandler invocationHandler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
try {
before(method, args);
//使用反射真正调用方法
result = method.invoke(target_animal, args);
after(method, result);
} catch (Exception e) {
//如果反射出现异常,就会进入到catch块
System.out.println("方法执行异常-日志-方法名" + method.getName()
+ "-异常类型=" + e.getClass().getName());//横切关注点-异常通知
e.printStackTrace();
} finally {//无论是否出现异常,最终都会执行到 finally{}
//也是一个横切关注点-最终通知
System.out.println("方法最终结束-日志-方法名-" + method.getName());
}
return result;
}
};
//创建代理对象
SmartAnimal proxy = (SmartAnimal) Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
return proxy;
}
}
2.对土方法进行解耦-开发简易的AOP类
上面的代码因为前后置等处理方法都写在同一个类中,造成代码耦合度高的问题。因此,更好的解决方法是新建一个类MyAOP,在该类中进行处理方法的编写,然后在MyProxyProvider类中调用该类的方法。
MyAOP类:
package com.li.aop.proxy3;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
* @author 李
* @version 1.0
* 自己写的一个极简AOP类
*/
public class MyAOP {
//定义一个方法,在目标对象执行前执行
public static void before(Method method, Object[] args) {
System.out.println("MyAOP-方法执行开始-日志-方法名-" + method.getName() +
"-参数 " + Arrays.toString(args));//前置通知
}
//定义一个方法,在目标对象执行后行
public static void after(Method method, Object result) {
System.out.println("MyAOP-方法执行正常结束-日志-方法名-" + method.getName()
+ "-结果 result = " + result);//返回通知
}
}
3.再次分析-提出Spring AOP
使用上面的办法仍存在一些问题:
- 不够灵活:假设被代理对象有很多方法,而我们只想仅对其中一个方法进行处理,当前的代码还不能实现这个需求
- 复用性差:假如有一个新的接口USBInterface,Phone类实现了这个接口,现在我们想要Phone类去调用之前MyAOP中的方法。但MyAOP类的方法是根据之前的SmartAnimal接口的方法写的,因此不能很好的适用于新的接口及其实现类
- 硬编码:没有注解和反射的支撑
5.AOP的基本介绍
1.什么是AOP?
官方文档:核心技术 (spring.io)
AOP全称:aspect oriented programming,即面向切面编程。
AOP 是一种编程思想,是面向对象编程(OOP)的一种补充。面向对象编程将程序抽象成各个层次的对象,而面向切面编程是将程序抽象成各个切面。
2.A