Spring的AOP


关于AOP

AOP(Aspect Orient Programming),也就是面向切面编程,是作为面向对象编程的补充。

    面向对象编程是静态地将程序分解成各个层次的对象,面向切面编程是动态地将程序运行过程分解成各个切面。

在实际应用中,AOP常用于处理一些具有横切性质(各个模块中的交叉关注点)的系统级服务,如事务管理、安全检查、缓存、对象池管理等

AspectJ框架

AspectJ是一个基于Java语言的AOP框架,即Eclipse的一个开源子项目,提供了强大的AOP功能。

其主要包括两部分:第一部分定义了如何表达、定义AOP编程中的语法规范,很多其他语言都借鉴了AspectJ中的很多设计,如从spring2.0开始,spring AOP引入了对AspectJ的支持,并使自身的APIAspectJ保持一致;另外一部分是工具部分,包括编译器、调试工具等。

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 AOP的支持

 

    Spring默认采用Java动态代理来创建AOP代理,也可以强制使用CGLIB代理;

    SpringAOP通常和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>
 

你可能感兴趣的:(spring)