Posted on 2010-06-01 01:24
Gavin.lee 阅读(862)
评论(0) 编辑 收藏 所属分类:
SSH2 --Spring
AOP面向切面编程(最突出的是处理权限控制,在本文中,主要介绍日志处理):
一、由无组件实现AOP引出Spring AOP:
1. 使用JDK中的Proxy技术实现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
{


/** *//**

*要处理的对象(也就是我们要在方法的前后加上业务逻辑的对象,如例子中的PersonServiceBean)

*/

private Object targetObject;



/** *//**

*动态生成目标对象的代理

*@paramtargetObject

*@return

*/


public Object createProxyIntance(Object targetObject)
{

this.targetObject = targetObject;

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

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

}



/** *//**

*要处理的对象中的每个方法会被此方法送去JVM调用,也就是说,要处理的对象的方法只能通过此方法调用

*/

@Override

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


throws Throwable
{ //环绕通知

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实现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方式实现目标对象的代理

*CGLIB代理:实现原理类似于JDK动态代理,只是它在运行期间生成的代理对象是针对目标类扩展的子类。CGLIB是高效的代码生成包,底层是依靠ASM(开源的java字节码编辑类库)操作字节码实现的,性能比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;

}

}


我们省去了业务模块的代码,因为这是完全独立于业务逻辑的,可以单独由一个完全不懂业务的人管理。测试用例如下:
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中,突出的就是业务逻辑的处理,AOP则是建立在业务逻辑处理的切面上,所以可以通过建立模块、业务层面的切面来对业务逻辑方法进行追踪
二、Spring提供了两种切面使用方式:
1. 基于xml配置方式进行AOP开发 (鄙人喜欢注解方式,xml配置方式暂不做研究O(∩_∩)O~)
2. 基于注解方式进行AOP开发
定义切面
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之后所要做的事情就是通知。通知分为前置通知,后置通知,异常通知,最终通知,环绕通知
Target(目标对象):代理的目标对象
Weave(织入):指将aspects应用到target对象并且导致proxy对象创建的过程称为织入
Introduction(引入):在不修改类代码的前提下,introduction可以在运行期为类动态的添加一些方法或field