3.spring中面向切面的使用

  1. BeanPostProcessor接口的使用

 

BeanPostProcessor接口用在bean生成后将放入ApplicationContext前进行一些必要的处理,它有两个方法,分别在调用bean配置的init-method前后执行(如果配置了的话),本接口的实现类常常结合动态代理生成bean的代理类型:

class MyProxyClass {

    private Object target;

 

    public MyProxyClass(Object target) {

       this.target = target;

    }

 

    public Object getNewProxy() {

       return Proxy.newProxyInstance(target.getClass().getClassLoader(),

              target.getClass().getInterfaces(), new InvocationHandler() {

 

                  public Object invoke(Object proxy, Method method,

                         Object[] args) throws Throwable {

                     System.out.println("you can do something here!!");

                     Object obj = method.invoke(target, args);

                     System.out.println("you can do something here!!");

                     return obj;

                  }

              });

    }

}

 

接口使用如下,接口使用如下,一般只要在postProcessAfterInitialization里面配置后即可(事实上这在实际开发中很少使用,一般会使用spring提供的组件,但其底层是使用这些的)

public class MyBeanPostProcessor implements BeanPostProcessor {

 

    public Object postProcessAfterInitialization(Object bean, String id)

           throws BeansException {

      

//参数Object 为生成的bean id 为该bean在配置文件中的id,这里我们一该用动态代理来生成一个代理对象返回

       return new  MyProxyClass(bean).getNewProxy();

    }

 

    public Object postProcessBeforeInitialization(Object bean, String id)

           throws BeansException {

              return bean;

    }

 

}

 

配置如下:

    <bean id="myprocessor" class="edu.yzu.filter.MyBeanPostProcessor" />

如上配置后spring 会自动为每个生成的bean生成相应的代理,如上代理的的效果为在调用每个方法找对应此bean的id,,,我们可以使用动态代理来生成

 

  1. 对bean中方法的方法的拦截(既自定义的Advice)共有四种,分别为四个接口,继承此四个接口后分别实现对应的方法:

MethodBeforeAdvice(在方法调用之前)

    public void before(Method method, Object[] args, Object target)

           throws Throwable {

//要在方法调用之前执行的操作

    }

MethodInterceptor (在方法调用之前之后都可以用此接口中的一个方法得到)

    AfterReturningAdvice(在方法返回以后)

    public void afterReturning(Object returnValue, Method method, Object[] args,

           Object targer) throws Throwable {

       //在方法调用之后 要执行的操作

    }

    ThrowsAdvice(在方法抛出异常以后会拦截)

public void afterThrowing(Exception e) {

       Session session=HibernateSessionFactory.getSessionFactory().getCurrentSession();

       session.getTransaction().rollback();

    }

注意:ThrowsAdvice接口中没有任何方法,但是使用此接口必须给出的方法签名为:afterThrowing,它可以重载多次,当相应的异常发生后调用对应的处理方法

使用:在配置文件中配置自定义的Advice,比如我有一个 TranstionManager类,它用来控制事务,实现了MethodInterceptor,如下!

public class TranstionManager implements MethodInterceptor {

    public Object invoke(MethodInvocation invocation) throws Throwable {

       Session session = HibernateSessionFactory.getSessionFactory()

              .getCurrentSession();

       Transaction trans = session.getTransaction();

       trans.begin();

       Object obj = invocation.proceed();

       trans.commit();

       return obj;

    }

}

文件的配置如下:

    <bean id="transtionmanager" class="edu.yzu.filter.TranstionManager"/>

另外有一个bean即为拦截的目标对象,为其生成代理对象,该bean的配置如下:

<bean id="userDao" class="edu.yzu.dao.impl.UserDaoImpl"/>

   

    <bean id="userBiz" class="edu.yzu.biz.impl.UserBizImpl">

    <property name="userDao">

    <ref local="userDao"/>//将userDao注入到到UserBizImpl中

    </property>

    </bean>

下面为userBiz生成代理对象的bean使用时用ApplicationContext对象实例applicationContext调用代理对象的方法为:applicationContext.getBean(“userBizImpl”);

<bean id="userBizImpl" class="org.springframework.aop.framework.ProxyFactoryBean">

    <property name="target">

    <ref local="userBiz"/>//指定给哪个目标对象建立代理

    </property>

    <property name="interceptorNames">

    <list>

    <value>transtionmanager</value>

//使用的Advice, 可以配置多个

    </list>

    </property>

    <property name="interfaces">

    <list>

    <value>edu.yzu.biz.UserBiz</value>

//指定要代理目标对象的哪个的接口

    </list>

    </property>

    </bean>

(上面是为实现接口的类生成代理) 缺点:一旦为一个bean指定代理,则bean中的所有方法都会被代理,不能指定为特定的方法指定代理,没有体现面向切面的特点!优点,依然可以拿到代理前的bean对象。如果没有实现任何接口,则不必要加name=”interfaces” 的项,但要加<property name="proxyTargetClass">

       <value>true</value>

       </property>表示这个bean没有实现任何接口,spring为它生成它的子类(cglib实现)

 

  1. 切面=切入点+切入内容。既为:aspect=pointcut+advice  spring 中切面用advisor表示,可以在配置文件中配置。切入的内容即为我们自定义的类型,它实现四个接口的的任何一个。切入点即为要切入内容的目标类型的方法:由此可知切面的配置也要配置这两项!

l         为一个bean配置一个advisor ,一个advisor里面只能有一个advice,但是可以给此advisor指定几个切入点,方法如下:

     <bean id="myadvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">

    <property name="advice">

    <ref local="transtionmanager"/>

    </property>

    <property name="mappedNames">

    <list>

    <value>addProduct</value>

    <value>deleteProductById</value>

    <value>getAllProducts</value>

    <value>getProduct</value>

    <value>getProducts</value>

    <value>updateProduct</value>

    </list>

    </property>

</bean>

这个Advisor只指定的advice为transtionmanager 为切入的内容,切入点为list只的几个方法名,既所代理的bean中,只有方法名相同的才能被切入。这正是面向切面的思想所在,advisor用法如下:

<bean id="productBizImpl" class="org.springframework.aop.framework.ProxyFactoryBean">

    <property name="target">

    <ref local="productBiz"/>

    </property>

    <property name="interceptorNames">

    <list>

    <value>myadvisor</value>

    <value>exceptionadvice</value>//这个是没有包装的advice,配置如下:

//<bean id="exceptionadvice" class="edu.yzu.filter.ExceptionFilter"/>

    </list>

    </property>

    <property name="interfaces">

    <list>

    <value>edu.yzu.biz.ProductBiz</value>

    </list>

    </property>

</bean>

这样做的好处体现了面向切面的思想,既给指定的切入点切入想要执行的内容。

 

下面是为多个bean指定多个advisor的方法,似乎也是最为常用的。

 

l         第一种:为多个bean同时指定多个advisor

Advisor配置不变,如下

     <bean id="myadvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">

    <property name="advice">

    <ref local="transtionmanager"/>

    </property>

    <property name="mappedNames">

    <list>

    <value>addProduct</value>

    <value>deleteProductById</value>

    <value>getAllProducts</value>

    <value>getProduct</value>

    <value>getProducts</value>

    <value>updateProduct</value>

    </list>

    </property>

</bean>

 

指定代理的目标对象的配置如下,既为哪些目标bean生成代理

    <bean id="autoProxy"

       class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">

       <property name="interceptorNames">

           <list>

              <value>myadvisor</value>

              <value>exceptionadvisor</value>

//自定义的advisor

           </list>

       </property>

       <property name="beanNames">

           <list>

              <value>userBiz</value>

              <value>productBiz</value>

//生成代理的目标对象

           </list>

       </property>

    </bean>

优点:可以同时为多个bean指定多个advisor。不足,因为是自动的为指定的bean生成代理,所以不能再得到原来的bean,只能拿到代理后的bean对象

 

l         第二种:为多个bean同时指定多个advisor

完整配置如下:

    <bean id="userBiz" class="edu.yzu.biz.impl.UserBizImpl">

       <property name="userDao">

           <bean id="userDao" class="edu.yzu.dao.impl.UserDaoImpl" />

       </property>

    </bean>

    <bean id="productBiz" class="edu.yzu.biz.impl.ProductBizImpl">

       <property name="productDao">

           <bean id="productDao" class="edu.yzu.dao.impl.ProductDaoImpl" />

       </property>

</bean>

 

<bean id="myadvisor"

       class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">

       <property name="advice">

           <bean id="transtionmanager" class="edu.yzu.filter.TranstionManager" />

       </property>

       <property name="mappedNames">

           <list>

              <value>addProduct</value>

              <value>deleteProductById</value>

              <value>getAllProducts</value>

              <value>getProduct</value>

              <value>getProducts</value>

              <value>updateProduct</value>

           </list>

       </property>

    </bean>

 

    <bean id="exceptionadvice"

       class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">

       <property name="advice">

           <bean id="exadvice" class="edu.yzu.filter.ExceptionFilter" />

       </property>

       <property name="mappedNames">

           <list>

              <value>addProduct</value>

              <value>deleteProductById</value>

              <value>getAllProducts</value>

              <value>getProduct</value>

              <value>getProducts</value>

              <value>updateProduct</value>

           </list>

       </property>

</bean>

 

<bean id="defaultautoproxy"

    class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>

优点,可以同时多个bean指定多个,advisor,缺点:可控性差。会为整个配置文件的所有的非advisor的bean都指定所有的advisor。注意事项,不必要的bean不要放在一个配置文件中,或者放在另外一个bean的内部,但是这样的bean对外界不可见,即不可用ApplicationContext的对象通过getBean得到!(实际用得不多)

posted @ 2010-05-03 17:35  沉兮  阅读(1014)  评论(0编辑  收藏  举报