Spring源码阅读(十一)—AOP补充
AOP面向切面编程是面向对象编程的一种补充,广泛应用于事务,日志等场景;
AOP实现的关键在于AOP框架能够为目标类创建AOP代理,AOP代理根据创建的形式分为静态代理和动态代理;
静态代理是指在编译期间生成代理类,也成为编译时增强;动态代理是指运行期间借助JDK动态代理或者CGLIB等在内存中临时生成动态代理类,也称为运行时增强;
Spring AOP是运行时增强,AspectJ是编译时增强;Spring AOP为了简化配置使用了和AspectJ一样的注解,但是Spring AOP在运行是依旧是基于动态代理的运行时增强;
个人主页:tuzhenyu’s page
原文地址:Spring源码阅读(十一)—AOP补充
(1)JDK动态代理或CGLIB实现简单的AOP
JDK动态代理实现简单AOP通过定义被代理目标接口,目标实现类,实现了InvacationHandler接口的AOP逻辑实现类,通过Proxy类的newProxyInstance()方法动态生成代理类;
- 代理目标接口
public interface ForumService {
public void addTopic();
public void removeTopic();
}
- 代理目标实现类
public class ForumServiceImpl implements ForumService {
public void addTopic(){
System.out.println("in the addTopic");
}
public void removeTopic(){
System.out.println("in the removeTopic");
}
}
- 代理横切织入代码
public class PerformanceHandler implements InvocationHandler{
private Object target;
public PerformanceHandler(Object target){
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
System.out.println("begin monitor...");
Object obj = method.invoke(target,args);
System.out.println("end monitor...");
return obj;
}
}
- 代理横测试类
public class Main {
public static void main(String[] args) {
ForumService target = new ForumServiceImpl();
PerformanceHandler handler = new PerformanceHandler(target);
ForumService proxy = (ForumService) Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
handler
);
proxy.addTopic();
proxy.removeTopic();
}
}
(2)通过ProxyFactory简化AOP的实现
为了简化AOP实现过程,可以使用ProxyFactory类,ProxyFactory类是对JDK动态代理和CGLIB动态代理的一个封装,将定义好的目标被代理类和增强Adviceh注入到ProxyFactory中生成代理类实现AOP功能;
- 定义增强
public class UserBeforeAdvice implements MethodBeforeAdvice{
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("before the method");
}
}
- 在XML配置文件中将增强和目标代理类注入到ProxyFactoryBean中
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="advice" class="aspectj.UserBeforeAdvice"></bean>
<bean id="target" class="aspectj.UserServiceImp"></bean>
<bean id="userService" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces" value="aspectj.UserService"></property>
<property name="InterceptorNames" value="advice"></property>
<property name="target" value="target"></property>
</bean>
</beans>
(3)创建切点切面细化AOP操作
Spring通过切点定位到某些类的特定方法上,切点结合增强封装成切面用来具体实现AOP功能
- 定义切面类,在切面类中通过ClassFilter和MethodMatcher进行切点匹配;切面是对切点和增强的封装;
public class UserAdvisor extends StaticMethodMatcherPointcutAdvisor {
public boolean matches(Method method, Class<?> aClass) {
return "addUser".equals(method.getName());
}
}
- 在XML配置文件中将增强注入到切面中
<bean id="advice" class="aspectj.UserBeforeAdvice"></bean>
<bean id="advisor" class="aspectj.UserAdvisor">
<property name="advice" value="advice"></property>
</bean>
- 在XML配置文件中将切面和目标代理类注入到ProxyFactoryBean中
<bean id="advice" class="aspectj.UserBeforeAdvice"></bean>
<bean id="advisor" class="aspectj.UserAdvisor">
<property name="advice" value="advice"></property>
</bean>
<bean id="target" class="aspectj.UserService"></bean>
<bean id="userService" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces" value="aspectj.Services"></property>
<property name="InterceptorNames" value="advisor"></property>
<property name="target" value="target"></property>
</bean>
(4) 通过自动创建代理简化AOP实现
使用ProxyFactoryBean实现AOP,每个需要被代理的Bean都需要使用一个ProxyFactoryBean进行配置;Spring提供了自动代理机制,底层使用BeanPostProcessor实现,在调动getBean()方法获取bean实例时会自动判断该类是否与切面匹配如果匹配则创建代理实例,否则创建普通实例;Spring的自动创建代理主要通过BeanNameAutoProxyCreator类,DefaultAdvisorAutoProxyCreator类,AnnocationAwareAspectjAutoProxyCreator类实现;
BeanNameAutoProxyCreator类:主要是为一组特定beanName的bean自动创建代理类,代理全部的方法;
DefaultAdvisorAutoProxyCreator类:扫描容器中的所有Advisor切面,自动将匹配的切面应用到Bean中;
AnnocationAwareAspectjAutoProxyCreator类:对AspectJ注解进行解析,扫描容器中的所有Advisor切面,自动将匹配的切面应用到Bean中;
定义切面类,在切面类中通过ClassFilter和MethodMatcher进行切点匹配;切面是对切点和增强的封装;
public class UserAdvisor extends StaticMethodMatcherPointcutAdvisor {
public boolean matches(Method method, Class<?> aClass) {
return "addUser".equals(method.getName());
}
}
- 在XML配置文件中将增强注入到切面中
<bean id="advice" class="aspectj.UserBeforeAdvice"></bean>
<bean id="advisor" class="aspectj.UserAdvisor">
<property name="advice" value="advice"></property>
</bean>
- 定义DefaultAdvisorAutoProxyCreator实例,自动扫描容器内的切面,并在调用getBean()是判断是否匹配,如果匹配则创建相应的代理类;
<bean id="advice" class="aspectj.UserBeforeAdvice"></bean>
<bean id="advisor" class="aspectj.UserAdvisor">
<property name="advice" value="advice"></property>
</bean>
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"></bean>
<bean id="userService" class="aspectj.UserService"></bean>
(5) 通过AspectJ注解进一步简化AOP配置
- 利用@Aspect定义切面类,将增强和切点结合在切面类中
@Aspect
@Compent
public class UserAdvisor {
@Before("execution(* addUser(...))")
public void before(){
System.out.println("in the before");
}
}
- 定义AnnocationAwareAspectjAutoProxyCreator实例开启AspectJ注解模式,自动扫描容器内的切面,并在调用getBean()是判断是否匹配,如果匹配则创建相应的代理类;
<bean class="org.springframework.aop.framework.autoproxy.AnnocationAwareAspectjAutoProxyCreator"></bean>
如果使用了aop命名空间则使用aop标签定义
<aop:aspectj-autoproxy>
总结
Spring AOP主要是由sping-aop和sping-aspects组成;
AOP是一种面向切面编程的思想,是对面向对象的一种补充,在日志以及事务管理等方面有着较多的应用;
AOP实现的关键在于AOP框架能够为目标类创建AOP代理,AOP代理根据创建的形式分为静态代理和动态代理;静态代理是指子啊编译期生成代理类,动态代理是指在运行期间在内存中生成临时代理类;Spring AOP是动态代理,AspectJ是静态代理,虽然Spring引入Aspects包支持AspecJ注解等,但是底层代理实现仍然是通过动态代理;
Spring AOP实现
可以通过JDK动态代理或者CGLIB动态代理直接实现,以JDK动态代理为例,定义目标接口,被代理目标类和实现了AOP逻辑的实现了InnovocationHandler的处理类,调用Proxy类的newProxyInstance()方法生成代理类;
为了简化配置可以使用ProxyFactoryBean,将切点或切面,被代理目标类注入ProxyFactoryBean中生成代理类;
为了进一步简化配置,可以定义自动创建类autoProxyCreator,会在bean实例创建时,搜索容器内的切面,如果匹配则生成代理类实例,如果不匹配则生成普通实例;
为了进一步简化配置,使用AspectJ注解,在切面类上使用@Aspect注解,在容器初始化时会将该切面类加载到容器中,在bean实例创建时,搜索容器内的切面,如果匹配则生成代理类实例,如果不匹配则生成普通实例