Spring2.5采用动态代理或cglib来实现aop

    技术2025-05-07  18

    动态代理,cglib,aop 

     

    1)

    public class JDKProxy implements InvocationHandler {

    private Object targetObject;//代理的目标对象

    public Object createProxyInstance(Object targetObject){

    this.targetObject = targetObject;

    /*

    * 第一个参数设置代码使用的类装载器,一般采用跟目标类相同的类装载器

    * 第二个参数设置代理类实现的接口

    * 第三个参数设置回调对象,当代理对象的方法被调用时,会委派给该参数指定对象的invoke方法

    */

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

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

    }

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

    throws Throwable {

        PersonServiceBean bean=(PersonServiceBean)this.targetObject;

       Object result=null

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

    result=method.invoke(this.targetObject, args);//把方法调用委派给目标对象

                  }

                return result;

    }

    }

     

    2)

    public class PersonServiceBean implements PersonService{

    private String user=null;

    public String getUser(){

    return user;

    }

     

    public PersonServiceBean(){}

    public PersonServiceBean(String user){

    this.user=user;

    }

    public void save(String name){

    System.out.println("我是save()方法");

    }

     

    }

     

    3)

    JDKProxy factory=new JDKProxy();

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

    service.save("888");

     

    4)如果PersonServiceBean 没有实现PersonService

     

    import net.sf.cglib.proxy.Enhancer;

    import net.sf.cglib.proxy.MethodInterceptor;

    import net.sf.cglib.proxy.MethodProxy;

     

    public class CGlibProxyFactory implements MethodInterceptor{

    private Object targetObject;

    public Object createProxyInstance(Object targetObject){

     

    this.targetObject=targetObject;

     Enhancer enhancer=new Enhancer();

     enhancer.setSuperclass(this.targetObject.getClass());//非final修饰符的所有方法

    enhacer.setCallback(this);

    return enhancer.create();

     

     

    }

     

    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){

     

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

           try{

    result=methodProxy .invoke(this.targetObject, args);//把方法调用委派给目标对象

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

              }catch(RuntimeException e){

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

                  }finally{ 

                 //finallyadvice() -->最终通知

     

                 }

     

     

          }

                return result;

    }

     

    }

     

    还有一种通知叫-->环绕通知

     

    5)相应测试代码如下

      CGlibProxyFactory factory=new CGlibProxyFactory();

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

    service.save("99");

     

    6)

    Aspect(切面):指横切性关注点的抽象即为切面,它与类相似,只是两者的关注点不一样,

          类是对物体特征的抽象,而切面横切性关注点的抽象.

     

    joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,

              因为spring只支持方法类型的连接点,实际上joinpoint还可以是field或类构造器)

     

    Pointcut(切入点):所谓切入点是指我们要对那些joinpoint进行拦截的定义.

     

    Advice(通知):所谓通知是指拦截到joinpoint之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知

     

    Target(目标对象):代理的目标对象

     

    Weave(织入):指将aspects应用到target对象并导致proxy对象创建的过程称为织入.

     

    Introduction(引入):在不修改类代码的前提下, Introduction可以在运行期为类动态地添加一些方法或Field.

     

     

    7)

    要进行AOP编程,首先我们要在spring的配置文件中引入aop命名空间:

    <beans xmlns="http://www.springframework.org/schema/beans"

           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

           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/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">

    </beans>

     

    Spring提供了两种切面声明方式,实际工作中我们可以选用其中一种:

    基于XML配置方式声明切面。

    基于注解方式声明切面。

     

    8) 使用注释方式 进行aop开发要在applicationContext中加入<aop:aspectj-autoproxy/>

      在类前加入@Aspect

       把这个拦载类放到spring的配置文件 中

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

     

     

    @Aspect

    public class MyInterceptor{

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

    private void anyMethod() {}//声明一个切入点

    @Before("anyMethod() && args(userName)")//定义前置通知 并且此前置通知只拦截带有一个参数,且类型为String的方法

    public void doAccessCheck(String userName) {

    }

    @AfterReturning(pointcut="anyMethod()",returning="result")//定义后置通知

    public void doReturnCheck(String result) {

    }

    @AfterThrowing(pointcut="anyMethod()", throwing="ex")//定义例外通知

        public void doExceptionAction(Exception ex) {

    }

    @After("anyMethod()")//定义最终通知

    public void doReleaseAction() {

    }

    @Around("anyMethod()")//环绕通知

    public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {

    return pjp.proceed();//确保后面的切面和业务bean都得到执行

                       //适合作为权限拦截的处理

    }

    }

     

    前置通知-->环绕通知-->业务方法-->后置通知--->最终通知-->环绕通知

    前置通知->业务方法-->异常通知-->最终通知

     

     

    8) 使用配置文件 进行aop开发

    普通的类定义

    public class LogPrint {

    public void doAccessCheck() {}定义前置通知

    public void doReturnCheck() {}定义后置通知

        public void doExceptionAction() {}定义例外通知

    public void doReleaseAction() {}定义最终通知

    public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {

    return pjp.proceed();环绕通知

    }

    }

     

    <bean id="orderservice" class="cn.itcast.service.OrderServiceBean"/>

    <bean id="log" class="cn.itcast.service.LogPrint"/>

    <aop:config>

      <aop:aspect id="myaop" ref="log">

       <aop:pointcut id="mycut" expression="execution(* cn.itcast.service..*.*(..))"/>

       <aop:before pointcut-ref="mycut" method="doAccessCheck"/>

       <aop:after-returning pointcut-ref="mycut" method="doReturnCheck "/>

       <aop:after-throwing pointcut-ref="mycut" method="doExceptionAction"/>

       <aop:after pointcut-ref="mycut" method=“doReleaseAction"/>

       <aop:around pointcut-ref="mycut" method="doBasicProfiling"/>

      </aop:aspect>

    </aop:config>

     

     

    9)execution(java.lang.String cn.itcast.service..*.*(..))  //拦截返回值为String  service包下及其子包的所有类的所有方法

       execution(* cn.itcast.service..*.*(java.lang.String,..))  //拦截方法的第一个参数是String,其他参数不限,包括只有一个参数

      execution(!void cn.itcast.service..*.*(..))  //返回值不是void

    execution(* cn.itcast.service.impl.PersonServiceBean.*(..)) 

    最新回复(0)