Posted on 2010-06-01 01:24
Gavin.lee 閱讀(867)
評論(0) 編輯 收藏 所屬分類:
SSH2 --Spring
AOP面向切面編程(最突出的是處理權限控制,在本文中,主要介紹日志處理):
一、由無組件實現(xiàn)AOP引出Spring AOP:
1. 使用JDK中的Proxy技術實現(xiàn)AOP功能
package cn.itcast.aop;

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

import java.lang.reflect.Proxy;

import cn.itcast.service.impl.PersonServiceBean;


public class JDKProxyFactory implements InvocationHandler
{


/** *//**

*要處理的對象(也就是我們要在方法的前后加上業(yè)務邏輯的對象,如例子中的PersonServiceBean)

*/

private Object targetObject;



/** *//**

*動態(tài)生成目標對象的代理

*@paramtargetObject

*@return

*/


public Object createProxyIntance(Object targetObject)
{

this.targetObject = targetObject;

return Proxy.newProxyInstance(this.targetObject.getClass().getClassLoader(),

this.targetObject.getClass().getInterfaces(), this);

}



/** *//**

*要處理的對象中的每個方法會被此方法送去JVM調(diào)用,也就是說,要處理的對象的方法只能通過此方法調(diào)用

*/

@Override

public Object invoke(Object proxy, Method method, Object[] args)


throws Throwable
{ //環(huán)繞通知

PersonServiceBean bean = (PersonServiceBean) this.targetObject;

Object result = null;


if(bean.getUser()!=null)
{

//
.. advice()-->前置通知

System.out.println(method.getName() + "is called¡¤¡¤¡¤¡¤¡¤¡¤");



try
{

result = method.invoke(targetObject, args);

// afteradvice() -->后置通知


} catch (RuntimeException e)
{

//exceptionadvice()--> 例外通知


}finally
{

//finallyadvice(); -->最終通知

}

}

return result;

}

}


2. 使用CGLIB實現(xiàn)AOP功能與AOP概念解釋
package cn.itcast.aop;

import java.lang.reflect.Method;

import cn.itcast.service.impl.PersonServiceBean;

import net.sf.cglib.proxy.Enhancer;

import net.sf.cglib.proxy.MethodInterceptor;

import net.sf.cglib.proxy.MethodProxy;


/** *//**

*CGLIB方式實現(xiàn)目標對象的代理

*CGLIB代理:實現(xiàn)原理類似于JDK動態(tài)代理,只是它在運行期間生成的代理對象是針對目標類擴展的子類。CGLIB是高效的代碼生成包,底層是依靠ASM(開源的java字節(jié)碼編輯類庫)操作字節(jié)碼實現(xiàn)的,性能比JDK強。

*/


publicclass CGlibProxyFactory implements MethodInterceptor
{

private Object targetObject;


public Object createProxyIntance(Object targetObject)
{

this.targetObject = targetObject;

Enhancer enhancer = new Enhancer();

enhancer.setSuperclass(this.targetObject.getClass());//非final

enhancer.setCallback(this);

return enhancer.create();

}

@Override

public Object intercept(Object proxy, Method method, Object[] args,


MethodProxy methodProxy) throws Throwable
{

PersonServiceBean bean = (PersonServiceBean) this.targetObject;

Object result = null;


if(bean.getUser()!=null)
{

result = methodProxy.invoke(targetObject, args);

}

return result;

}

}


我們省去了業(yè)務模塊的代碼,因為這是完全獨立于業(yè)務邏輯的,可以單獨由一個完全不懂業(yè)務的人管理。測試用例如下:
package junit.test;

import org.junit.BeforeClass;

import org.junit.Test;

import cn.itcast.aop.CGlibProxyFactory;

import cn.itcast.aop.JDKProxyFactory;

import cn.itcast.service.PersonService;

import cn.itcast.service.impl.PersonServiceBean;


public class AOPTest
{

@BeforeClass


public static void setUpBeforeClass() throws Exception
{

}


@Test public void proxyTest()
{

JDKProxyFactory factory = new JDKProxyFactory();

PersonService service = (PersonService) factory.createProxyIntance(new PersonServiceBean("xxx"));

service.save("888");

}



@Test public void proxyTest2()
{

CGlibProxyFactory factory = new CGlibProxyFactory();

PersonServiceBean service = (PersonServiceBean) factory.createProxyIntance(new PersonServiceBean("xxx"));

service.save("999");

}

}
小結:在Spring中,突出的就是業(yè)務邏輯的處理,AOP則是建立在業(yè)務邏輯處理的切面上,所以可以通過建立模塊、業(yè)務層面的切面來對業(yè)務邏輯方法進行追蹤
二、Spring提供了兩種切面使用方式:
1. 基于xml配置方式進行AOP開發(fā) (鄙人喜歡注解方式,xml配置方式暫不做研究O(∩_∩)O~)
2. 基于注解方式進行AOP開發(fā)
定義切面
package cn.itcast.service;

import org.aspectj.lang.ProceedingJoinPoint;

import org.aspectj.lang.annotation.After;

import org.aspectj.lang.annotation.AfterReturning;

import org.aspectj.lang.annotation.AfterThrowing;

import org.aspectj.lang.annotation.Around;

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Before;

import org.aspectj.lang.annotation.Pointcut;


/** *//**

*注解方式定義切面

*/

@Aspect


publicclass MyInterceptor
{


@SuppressWarnings("unused")

@Pointcut("execution (* cn.itcast.service.impl.PersonServiceBean.*(..))")


privatevoid anyMethod()
{}//聲明一個切入點


@Before("anyMethod() && args(name)")


publicvoid doAccessCheck(String name)
{

System.out.println("前置通知:"+ name);

}


@AfterReturning(pointcut="anyMethod()",returning="result")


publicvoid doAfterReturning(String result)
{

System.out.println("后置通知:"+ result);

}


@After("anyMethod()")


publicvoid doAfter()
{

System.out.println("最終通知");

}


@AfterThrowing(pointcut="anyMethod()",throwing="e")


publicvoid doAfterThrowing(Exception e)
{

System.out.println("例外通知:"+ e);

}


@Around("anyMethod()")


public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable
{

//if(){//判斷用戶是否在權限

System.out.println("進入方法");

Object result = pjp.proceed();

System.out.println("退出方法");

//}

return result;

}

}

利用Spring 做AOP必須的組件包:
spring-framework-2.5.6"lib"cglib"cglib-nodep-2.1_3.jar

spring-framework-2.5.6"lib"aspectj"aspectjweaver.jar

spring-framework-2.5.6"lib"aspectj"aspectjrt.jar

spring-framework-2.5.6"lib"j2ee"common-annotations.jar

spring-framework-2.5.6"lib"jakarta-commons"commons-logging.jar

spring-framework-2.5.6"dist"spring.jar

Spring 配置:
<?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: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-2.5.xsd

http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd

http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">

<aop:aspectj-autoproxy />

<bean id="myInterceptor" class="cn.itcast.service.MyInterceptor" />

<bean id="personService" class="cn.itcast.service.impl.PersonServiceBean"></bean>

</beans>

測試用例:
package junit.test;

import org.junit.BeforeClass;

import org.junit.Test;

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import cn.itcast.service.PersonService;


publicclass SpringAOPTest
{

@BeforeClass


publicstaticvoid setUpBeforeClass() throws Exception
{

}

@Test


publicvoid interceptorTest()
{

ApplicationContext cxt = new ClassPathXmlApplicationContext("beans.xml");

PersonService personService = (PersonService) cxt.getBean("personService");

personService.save("xx");

}

}

三、AOP術語:
Aspect(切面):指橫切面關注點的抽象即為切面,它與類相似,只是兩者的關注點不一樣,類是對物體特征的抽象,而切面是橫切性關注點的抽象
Joinpoint(連接點):所謂連接點是指那些被攔截到的點。在Spring中,這些點指的是方法,因為spring只支持方法類型的連接點,實際上joinpoint還可以是field或類構造器
Pointcut(切入點):所謂的切入點是指我們要對那些joinpoint進行攔截的定義
Advice(通知):所謂的通知是指攔截到joinpoint之后所要做的事情就是通知。通知分為前置通知,后置通知,異常通知,最終通知,環(huán)繞通知
Target(目標對象):代理的目標對象
Weave(織入):指將aspects應用到target對象并且導致proxy對象創(chuàng)建的過程稱為織入
Introduction(引入):在不修改類代碼的前提下,introduction可以在運行期為類動態(tài)的添加一些方法或field