Posted on 2010-06-01 01:24
Gavin.lee 阅读(859)
评论(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