Spring Aop原理解析和使用示例
前言
众所周知,Spring拥有两大特性:IoC和AOP。IoC,英文全称Inversion of Control,意为控制反转。AOP,英文全称Aspect-Oriented Programming,意为面向切面编程。
今天我们的主题就是Spring的Aop的源码解析。
Spring Aop相关概念
Spring Aop基本原理
Spring Aop的实现的原理就是JDK的动态代理。核心思想就是利用动态代理模式,再方法执行前后或者出现异常时加入相关逻辑。
JDK动态代理入门
利用java的反射机制,使用Proxy.newProxyInstance创建代理类对象,从而代理目标对象的调用。
**目的:**在完成目标对象调用时,进行功能增强。
**大致实现:**使用反射包 java.lang.reflect , 里面有三个类 : InvocationHandler , Proxy。
Proxy.newProxyInstance:静态方法,用于创建代理对象。参数列表如下:
- ClassLoader loader 类加载器,负责向内存中加载对象的。 使用反射获取对象的ClassLoader类a, a.getCalss().getClassLoader(), 目标对象的类加载器。
- Class<?>[] interfaces: 接口, 目标对象实现的接口,也是反射获取的。
- InvocationHandler h : 我们自己写的,代理类要完成的功能。
InvocationHandler:接口类,实现目标对象的代理调用。接口方法如下:
- public Object invoke(Object proxy, Method method, Object[] args){}
- Object proxy: jdk创建的代理对象,无需赋值。
- Method method: 目标类中的方法,jdk提供method对象的。
- Object[] args: 目标类中方法的参数, jdk提供的。
动态代理举例
ClassLoader loader 类加载器,负责向内存中加载对象的。 使用反射获取对象的ClassLoader类a, a.getCalss().getClassLoader(), 目标对象的类加载器
Class<?>[] interfaces: 接口, 目标对象实现的接口,也是反射获取的。
InvocationHandler h : 我们自己写的,代理类要完成的功能。
InvocationHandler:接口类,实现目标对象的代理调用
动态代理举例
/**
* 接口类
*/
public interface IHelloWorld {
void publicSayHello();
}
/**
* 实现类
*/
public class HelloWorld implements IHelloWorld {
private void privateSayHello() {
System.out.println("private:hello world");
}
/**
* 接口实现方法
*/
public void publicSayHello() {
System.out.println("public:hello world");
}
}
/**
* 自定义动态代理
*/
public class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("start.");
Object obj = method.invoke(target, args);
System.out.println("end.");
return obj;
}
/**
* 获取动态代理对象
* @return 代理对象
*/
public Object getProxy() {
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
}
/**
* 测试类
*/
public class ProxyTest {
public static void main(String[] args) {
HelloWorld helloWorld = new HelloWorld();
MyInvocationHandler myInvocationHandler = new MyInvocationHandler(helloWorld);
Object object = myInvocationHandler.getProxy();
IHelloWorld object1 = (IHelloWorld)object;
object1.publicSayHello();
}
}
输出如下:
start.
public:hello world
end.
Spring Aop代码实现原理
Spring Aop的代码实现逻辑是嵌入在Spring Bean的生成过程中的。
-
Spring Bean的生成过程是什么样的?
Spring Bean的生成过程大致可以总结为"实例化" ==> “依赖注入” ==> “回调(Aware回调)” ==> “初始化” ==> BeanPostProcessor
-
Spring Aop的能力是利用Spring Bean生成过程中的BeanPostProcessor,对生成的实例进行动态代理的后置处理,使得Spring Bean生成后,拿到的是经过Spring动态代理之后的代理对象
代码示例:
// bean生命周期
// 实例化 -> 依赖注入 -> 回调(Aware回调) -> 初始化 -> AOP
private Object createBean(String beanName, BeanDefinition beanDefinition) {
Class clazz = beanDefinition.getType();
try {
Object instance = clazz.getConstructor().newInstance();
// 依赖注入
Field[] declaredFields = clazz.getDeclaredFields();
for (Field f : declaredFields) {
if (f.isAnnotationPresent(Autowired.class)) {
f.setAccessible(true);
Object value = getBean(f.getName());
f.set(instance, value);
}
}
// 回调
if (instance instanceof BeanNameAware) {
((BeanNameAware) instance).setBeanName(beanName);
}
// AOP BeanPostProcessor机制
for (BeanPostProcessor beanPostProcessor : beanPostProcessorArrayList) {
instance = beanPostProcessor.postProcessBeforeInitialization(beanName, instance);
}
// 初始化
if (instance instanceof InitializingBean) {
((InitializingBean) instance).afterPropertiesSet();
}
// AOP BeanPostProcessor机制
for (BeanPostProcessor beanPostProcessor : beanPostProcessorArrayList) {
instance = beanPostProcessor.postProcessAfterInitialization(beanName, instance);
}
return instance;
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
return null;
}
Spring BeanProcess接口:
public interface BeanPostProcessor {
Object postProcessBeforeInitialization(String beanName, Object bean);
Object postProcessAfterInitialization(String beanName, Object bean);
}
Spring Aop使用示例
基于配置文件的使用示例
<bean id="agentAdvisorXML" class="com.fufu.spring.aop.AgentAdvisorXML"/>
<!--Spring基于Xml的切面-->
<aop:config>
<!-- 定义切点函数 -->
<aop:pointcut id="singPointCut" expression="execution(* com.test.proxy.User.sing(..))"/>
<!-- 定义切面 order 定义优先级,值越小优先级越大-->
<aop:aspect ref="agentAdvisorXML" order="0">
<!--前置通知-->
<aop:before method="getMoney" pointcut-ref="singPointCut"/>
<!--后置通知-->
<aop:after method="writeReceipt" pointcut-ref="singPointCut"/>
</aop:aspect>
</aop:config>
基于注解的使用示例
-
开启@AspectJ注解支持
<aop:aspectj-autoproxy/>
-
在类的相应位置加上注解
/** * Created by zhoujunfu on 2018/9/7. * 基于注解的Spring AOP */ @Aspect @Component public class AgentAdvisor { @Before(value = "execution(* com.fufu.proxy.ShowService.sing(..))") public void getMoney() { System.out.println("get money"); } @After(value = "execution(* com.fufu.proxy.ShowService.sing(..))") public void writeReceipt() { System.out.println("write receipt"); } }
手撸Spring源码,精简易懂:https://download.csdn.net/download/jjs15259655776/85816604