天天看點

Advice隻有切面化之後才能顯現出AOP的巨大優勢

上一篇所講到的Advice,經過ProxyFactoryBean織入到Bean中,實際上是織入到Bean的聯接點上,這顯然不是我們想看到的,因為并不是所有方法都需要同樣的公用代碼。spring提供了切點(Pointcut)的概念,指真正需要織入Advice的聯接點,并且提供了專門的類org.springframework.aop.support.NameMatchMethodPointcutAdvisor把Advice和Pointcut結合成一個整體,叫切面(Advisor),這樣對Bean的方法就可以有選擇的進行處理。是以,Advice隻有切面化之後才能顯現出AOP的巨大優勢。

比如,我們對Dao類進行添加事務的處理,顯然隻有增,删,改才需要,而查詢方法就不再需要。

Dao類:

public class StudentDaoImpl implements StudentDao { 

  @Override 

  public void delete(Integer id) {//事務處理已經被提取出去了 

    Student stu=getStudentById(id); 

    Session session=HibernateUtil.getCurrentSession(); 

    session.delete(stu); 

  } 

  public Student getStudentById(Integer id) {//查詢不需要事務 

    Session session=HibernateUtil.openSession(); 

    Student stu=(Student)session.get(Student.class, id); 

    return stu; 

  @SuppressWarnings("unchecked") 

  public List<Student> getStudents() {//查詢不需要事務 

    String hql="from Student"; 

    List<Student> stus=session.createQuery(hql).list(); 

    return stus; 

  public void insert(Student stu) {//事務處理已經被提取出去了 

    session.save(stu); 

  public void modify(Student stu) {//事務處理已經被提取出去了 

    session.saveOrUpdate(stu); 

}

Advice:

public class TransactionAdvice implements MethodInterceptor { 

  public Object invoke(MethodInvocation invocation) throws Throwable { 

    try{ 

    Transaction trans=session.beginTransaction(); 

    trans.begin(); 

    System.out.println("====begin transaction===="); 

    Object ret=invocation.proceed(); 

    trans.commit(); 

    System.out.println("====commit transaction===="); 

    return ret; 

    }catch(Exception e){ 

      HibernateUtil.getCurrentSession().getTransaction().rollback() ; 

      System.out.println( "**** rollback transaction ****") ; 

      throw e ; 

    } 

配置檔案:

<beans> 

  <bean id="targetDao" class="com.yangfei.spring.advisor.dao.StudentDaoImpl"></bean> 

  <bean id="transAdvice" class="com.yangfei.spring.advisor.advice.TransactionAdvice"></bean> 

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

    <property name="advice"> 

      <ref local="transAdvice"/> 

    </property> 

    <property name="mappedNames"> 

      <list> 

        <value>insert</value> 

        <value>delete</value> 

        <value>modify</value> 

      </list> 

  </bean> 

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

    <property name="target"> 

      <ref bean="targetDao"/> 

    <property name="interceptorNames"> 

        <value>transAdvisor</value> 

      <property name="interfaces"> 

    <list> 

      <value>com.yangfei.spring.advisor.dao.StudentDao</value> 

    </list> 

  </property> 

</beans>

測試:

  public static void main(String[] args) { 

    ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml"); 

    StudentDao dao=(StudentDao)ctx.getBean("dao"); 

    //查 

    Student stu=dao.getStudentById(2); 

    System.out.println(stu); 

    List<Student> stus=dao.getStudents(); 

    for(Student s:stus){ 

      System.out.println(s); 

    /* 

    dao.delete(4); 

    Student s=new Student(); 

    s.setName("wangwu"); 

    s.setBirthday(new Date()); 

    dao.insert(s);*/ 

    Student s=new Student(); 

    s.setId(4); 

    s.setName("zhaoliu"); 

    s.setBirthday(new Date()); 

    dao.modify(s);

運作結果:

Hibernate: select student0_.id as id0_0_, student0_.name as name0_0_, student0_.birthday as birthday0_0_ from spring_student student0_ where student0_.id=?

Student: zhangsan

Hibernate: select student0_.id as id0_, student0_.name as name0_, student0_.birthday as birthday0_ from spring_student student0_

Student: yangfei

Student: lisi

Student: zhaoliu

====begin transaction====

Hibernate: delete from spring_student where id=?

====commit transaction====

Hibernate: select max(id) from spring_student

Hibernate: insert into spring_student (name, birthday, id) values (?, ?, ?)

Hibernate: update spring_student set name=?, birthday=? where id=?

不過這裡有個問題,ProxyFactoryBean一次隻能給一個Bean織入切面,如果我們Bean要足夠多的話,顯然會把配置檔案搞的非常龐大。幸運的是spring還提供了另一個類org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator,可以一次給多個Bean配置多個Advisor。當然,在使用Bean時,就不能直接用它BeanNameAutoProxyCreator的id了,而隻能使用Bean各自的id,取出來的就是代理對象了。

  <bean id="targetDao2" class="com.yangfei.spring.advisor.dao.StudentDaoImpl"></bean> 

  <bean id="test" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> 

    <property name="beanNames"> 

        <value>targetDao</value> 

        <value>targetDao2</value> 

      本文轉自NightWolves 51CTO部落格,原文連結:http://blog.51cto.com/yangfei520/246283,如需轉載請自行聯系原作者