Spring 2.5 采用动态代理或cglib来实现aop

来源:互联网 发布:自学php需要什么基础 编辑:程序博客网 时间:2024/04/26 00:52

动态代理,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.*(..)) 

原创粉丝点击