关于AOP
AOP(Aspect Orient Programming),也就是面向切面编程,是作为面向对象编程的补充。
面向对象编程是静态地将程序分解成各个层次的对象,面向切面编程是动态地将程序运行过程分解成各个切面。
在实际应用中,AOP常用于处理一些具有横切性质(各个模块中的交叉关注点)的系统级服务,如事务管理、安全检查、缓存、对象池管理等…。
AspectJ框架
AspectJ是一个基于Java语言的AOP框架,即Eclipse的一个开源子项目,提供了强大的AOP功能。
其主要包括两部分:第一部分定义了如何表达、定义AOP编程中的语法规范,很多其他语言都借鉴了AspectJ中的很多设计,如从spring2.0开始,spring AOP引入了对AspectJ的支持,并使自身的API与AspectJ保持一致;另外一部分是工具部分,包括编译器、调试工具等。
1.写测试类
Public aspect LogAspect{
//定义一个Pointcut,其名为logPointcut
Pointcut logPoincut()
:execution(void Hello.sayHello());
//在logPointcut之后执行下面代码块
After():logPointcut(){
System.out.println(“记录日志…”);
}
}
2.编译
Ajc –d logAspect.java
此处通过AspectJ的编译增强了Hello.class类的功能,因此AspectJ被称为编译时增强的AOP框架。
实质:
AOP框架特征:只处理程序执行中特定切入点(Pointcut),而不与具体某个具体类耦合。
AOP代理其实是由AOP框架动态生成一个对象,该对象即包含了目标对象的全部方法,也在特定切入点增强了处理(即增加了AOP方法);
结构示意图:
Spring 对AOP的支持
Spring默认采用Java动态代理来创建AOP代理,也可以强制使用CGLIB代理;
Spring的AOP通常和Spring Ioc容器一起使用,并没有提供一种全面的AOP解决方案与AspectJ竞争,如:spring目前仅支持将方法调用作为连接点(Joinpoint),如果需要把对Field的访问和更新也作为增强处理的连接点,需要考虑用AspectJ框架。
组成部分:
定义普通业务组件;
定义切入点,一个切入点可能横切多个业务组件;
定义增强处理,即在AOP框架为普通业务组件织入的动作处理。
AOP代理的方法:
= 增强处理 + 被代理对象的方法
加入包:
org.springframework.aop-3.1.1.RELEASE.jar
aspectjrt.jar
aspectjweaver.jar
aopalliance.jar
cglib-2.1.3.jar(缺少会出现Cannot proxy target class because CGLIB2…异常)
基于annotation的”零”配置
1、
spring.xml加入
<!-- 设置扫描组件 -->
<context:component-scan base-package="com.mvc.aop" annotation-config="true">
</context:component-scan>
<!-- 启动组件注解 -->
<context:annotation-config/>
<!-- 启动@AspectJ支持 -->
<aop:aspectj-autoproxy/>
2、定义Bean的增强效果
package com.mvc.aop;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
//定义一个切面,使用Aspect修饰后,spring 不会把该bean进行增强处理
@Aspect
public class BeforAdviceTest {
//所有方法执行作为切入点
@Before("excution(com.mvc.aop.*)")
public void authority(){
System.out.println("模拟执行权限检查...");
}
}
3、定义业务组件
package com.mvc.aop;
import org.springframework.stereotype.Component;
@Component
public class Chinese {
public String sayHello(String name){
return name + " hello,spring aop";
}
}
4、调用组件方法
New Chinese().sayHello(“test”); //输出test hello,spring aop.
基于Xml配置文件的管理方式
注:<aop:aspectj-autoproxy/>与Xml方式只能选取一种方法
1、XML的配置文件
<bean id="beforeAdviceBean" class="com.mvc.aop.BeforAdviceTest"></bean>
<aop:config>
<!-- 将BeforAdvicTest转换成切面Bean -->
<aop:aspect id="beforeAdviceAspect" ref="beforeAdviceBean" order="1">
<!-- 配置增强处理方法 -->
<aop:before method="authority" pointcut="execution(* com.mvc.aop.*.*(..))"/>
</aop:aspect>
</aop:config>
ProxyFactoryBean(一):只实现接口类型
1、xml的配置
<!-- 目标对象 -->
<bean id="chinese" class="com.mvc.aop.Chinese"></bean>
<!-- Advice类 -->
<bean id="logAdvisor" class="com.mvc.aop.English"></bean>
<bean id="human" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 指定目标对象 -->
<property name="target">
<ref local="chinese" />
</property>
<!-- 值为true时表示如果没有明确指定要代理的接口类型,会自动检测检测目标对象所实现的接口类型并进行代理 -->
<property name="proxyTargetClass">
<value>false</value>
</property>
<!-- 指定目标对象要实现的接口类型 -->
<property name="proxyInterfaces">
<list>
<value>com.mvc.aop.Human</value>
</list>
</property>
<!-- 可将多个Advice、拦截器、Advisor织入到目标对象 ,达到增强效果-->
<property name="interceptorNames">
<list>
<value>logAdvisor</value>
</list>
</property>
</bean>
2、Advice类
public class English implements MethodBeforeAdvice{
@Override
public void before(Method arg0, Object[] arg1, Object arg2)
throws Throwable {
System.out.println("hello, I am English!");
}
}
ProxyFactoryBean(二):加入RegexpMethodPointcutAdvisor
xml配置
<!-- 目标对象 -->
<bean id="chinese" class="com.mvc.aop.Chinese"></bean>
<!-- advice类 -->
<bean id="log" class="com.mvc.aop.English"></bean>
<bean id="human" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 指定目标对象 -->
<property name="target">
<ref local="chinese" />
</property>
<!-- 值为true时表示如果没有明确指定要代理的接口类型,会自动检测检测目标对象所实现的接口类型并进行代理 -->
<property name="proxyTargetClass">
<value>false</value>
</property>
<!-- 指定目标对象要实现的接口类型 -->
<property name="proxyInterfaces">
<list>
<value>com.mvc.aop.Human</value>
</list>
</property>
<!-- 可将多个Advice、拦截器、Advisor织入到目标对象 ,达到增强效果-->
<property name="interceptorNames">
<list>
<value>logAdvisor</value>
</list>
</property>
</bean>
<!--代理目标类的指定方法-->
<bean id="logAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice">
<ref bean="log"/>
</property>
<!--指定要代理的方法-->
<property name="patterns">
<value>.*say.*</value>
</property>
</bean>
MethodInterceptor配置方式:
自定义注解的代码:
package com.qunar.wireless.ugc.controllor.web;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface LoginRequired {
}
自定义的方法拦截器:
import javax.servlet.http.HttpServletRequest;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import com.qunar.wireless.ugc.controllor.web.LoginRequired;
/**
* @author tao.zhang
* @create-time 2012-2-31
*/
public class LoginRequiredInterceptor1 implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
Object[] ars = mi.getArguments();
for(Object o :ars){
if(o instanceof HttpServletRequest){
System.out.println("------------this is a HttpServletRequest Parameter------------ ");
}
}
// 判断该方法是否加了@LoginRequired 注解
if(mi.getMethod().isAnnotationPresent(LoginRequired.class)){
System.out.println("----------this method is added @LoginRequired-------------------------");
}
//执行被拦截的方法,切记,如果此方法不调用,则被拦截的方法不会被执行。
return mi.proceed();
}
}
配置文件:
<bean id="springMethodInterceptor" class="com.qunar.wireless.ugc.interceptor.LoginRequiredInterceptor1" ></bean>
<aop:config>
<!--切入点-->
<aop:pointcut id="loginPoint" expression="execution(public * com.qunar.wireless.ugc.controllor.web.*.*(..)) "/>
<!--在该切入点使用自定义拦截器-->
<aop:advisor pointcut-ref="loginPoint" advice-ref="springMethodInterceptor"/>
</aop:config>