上一篇所讲到的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);
  }

  @Override
   public Student getStudentById(Integer id) { //查询不需要事务
    Session session=HibernateUtil.openSession();
    Student stu=(Student)session.get(Student. class, id);
     return stu;
  }

  @SuppressWarnings( "unchecked")
  @Override
   public List<Student> getStudents() { //查询不需要事务
    Session session=HibernateUtil.openSession();
    String hql= "from Student";
    List<Student> stus=session.createQuery(hql).list();
     return stus;
  }

  @Override
   public void insert(Student stu) { //事务处理已经被提取出去了
    Session session=HibernateUtil.getCurrentSession();
    session.save(stu);
  }

  @Override
   public void modify(Student stu) { //事务处理已经被提取出去了
    Session session=HibernateUtil.getCurrentSession();
    session.saveOrUpdate(stu);
  }
}
 
Advice:
public class TransactionAdvice implements MethodInterceptor {
  @Override
   public Object invoke(MethodInvocation invocation) throws Throwable {
     try{
    Session session=HibernateUtil.getCurrentSession();
    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 >
     </ property >
   </ bean >
   < bean id ="dao" class ="org.springframework.aop.framework.ProxyFactoryBean" >
     < property name ="target" >
       < ref bean ="targetDao" />
     </ property >
     < property name ="interceptorNames" >
       < list >
         < value >transAdvisor </ value >
       </ list >
     </ property >
       < property name ="interfaces" >
     < list >
       < value >com.yangfei.spring.advisor.dao.StudentDao </ value >
     </ list >
   </ property >
   </ bean >
</ 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: zhangsan
Student: lisi
Student: zhaoliu
====begin transaction====
Hibernate: select student0_.id as id0_0_, student0_.name as name0_0_, student0_.birthday as birthday0_0_ from spring_student student0_ where student0_.id=?
Hibernate: delete from spring_student where id=?
====commit transaction====
====begin transaction====
Hibernate: select max(id) from spring_student
Hibernate: insert into spring_student (name, birthday, id) values (?, ?, ?)
====commit transaction====
====begin transaction====
Hibernate: update spring_student set name=?, birthday=? where id=?
====commit transaction====
 
不过这里有个问题,ProxyFactoryBean一次只能给一个Bean织入切面,如果我们Bean要足够多的话,显然会把配置文件搞的非常庞大。幸运的是spring还提供了另一个类org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator,可以一次给多个Bean配置多个Advisor。当然,在使用Bean时,就不能直接用它BeanNameAutoProxyCreator的id了,而只能使用Bean各自的id,取出来的就是代理对象了。
< beans >
   < bean id ="targetDao" class ="com.yangfei.spring.advisor.dao.StudentDaoImpl" > </ bean >
   < bean id ="targetDao2" 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 >
     </ property >
   </ bean >
   < bean id ="test" class ="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator" >

     < property name ="interceptorNames" >
       < list >
         < value >transAdvisor </ value >
       </ list >
     </ property >
     < property name ="beanNames" >
       < list >
         < value >targetDao </ value >
         < value >targetDao2 </ value >
       </ list >
     </ property >
   </ bean >
</ beans >