无线&移动互联网技术研发

换位思考·····
posts - 19, comments - 53, trackbacks - 0, articles - 283
  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理
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


只有注册用户登录后才能发表评论。


网站导航: