spring03 AOP、各种通知、一/多个切面例子

来源:互联网 发布:阿里云华南地区是哪里 编辑:程序博客网 时间:2024/06/03 21:58




一、 springAOP


       1、作用: 使得事务、日志、安全性框架、权限、目标方法之间完全是松耦合的
       
       2、组成
              1、切面:   事务、日志、安全性框架、权限等都是切面
              2、通知:   切面中的方法就是通知
              3、目标类 
              4、切入点   只有符合切入点,才能让通知和目标方法结合在一起
              5、织入:   形成代理对象的方法的过程
              注:代理对象的方法就是通知和目标方法的结合体
              
       3、相对于动态代理,省略了写拦截器的过程
       
       4、切入点表达式详解
       
              
        
        
       5、springAOP的具体加载步骤:
             1、当spring容器启动的时候,加载了spring的配置文件
             2、为配置文件中所有的bean创建对象
             3、spring容器会解析aop:config的配置 
                   解析切入点表达式,用切入点表达式和纳入spring容器中的bean做匹配
                      如果匹配成功,则会为该bean创建代理对象,代理对象的方法=目标方法+通知
                      如果匹配不成功,不会创建代理对象
             4、在客户端利用context.getBean获取对象时,如果该对象有代理对象则返回代理对象,
                      如果无代理对象,则返回目标对象


             5、如果目标类没有实现接口,则spring容器会采用cglib的方式产生代理对象,
                      如果实现了接口,会采用jdk的方式
       
              
       6、各种通知详解
             1、前置通知
                  1、在目标方法执行之前执行
                  2、无论目标方法是否抛出异常,都执行,因为在执行前置通知的时候,目标方法还没有执行,还没有遇到异常
                  例:  
                      ------------------------------------------------------------------------------
                      <aop:before method="beginTransaction" pointcut-ref="perform"/>
                      
                      // 前置通知
                      public void beginTransaction(){
                          System.out.println("before inform");
                          this.transaction = sessionFactory.getCurrentSession().beginTransaction();      
                      }
                      ------------------------------------------------------------------------------
                  
                  
             2、后置通知
                  1、在目标方法执行之后执行
                  2、当目标方法遇到异常,后置通知将不再执行
                  3、后置通知可以接受目标方法的返回值,但是必须注意:
                      后置通知的参数的类型为Object,且名称和配置文件中returning="var"的值是一致的
                  例:
                      ------------------------------------------------------------------------------
                      不带参数的
                          <aop:after-returning method="commit" pointcut-ref="perform" />
                          
                          // 后置通知
                          public void commit(){
                              System.out.println("after return inform");
                              this.transaction.commit();
                          }
                          
                          // 不带返回值的目标方法
                          public void savePerson(Person person) {
                              sessionFactory.getCurrentSession().save(person);
                          }
                        
                        
                      带参数的
                          <aop:after-returning method="commit" pointcut-ref="perform" returning="var"/>
                          
                          public void commit(Object var){
                              System.out.println("after return inform");
                              System.out.println(var);
                              this.transaction.commit();
                          }
                          
                          // 带返回值的目标方法
                          public String savePerson(Person person) {
                            //int i = 1/0;
                              System.out.println("目标方法");
                              return "返回值";
                          }
                      ------------------------------------------------------------------------------
                        
                           
             3、最终通知:
                  1、在目标方法执行之后执行
                  2、无论目标方法是否抛出异常,都执行,因为相当于finally
                  例:
                      ------------------------------------------------------------------------------
                        <aop:after method="fianllyMethod" pointcut-ref="perform"/>
                        
                        public void fianllyMethod(){
                            System.out.println("finally inform");
                        }
                      ------------------------------------------------------------------------------
                  
                  
             4、异常通知
                  1、接受目标方法抛出的异常信息
                  2、步骤
                       在异常通知方法中有一个参数Throwable  ex
                       在配置文件中
                          <aop:after-throwing method="throwingMethod" pointcut-ref="perform" throwing="ex"/>
                       注: throwing也要和切面中的异常通知的类型为Throable的参数名称保持一致
                  例:
                      -------------------------------------------------------------------------------
                        <aop:after-throwing method="throwingMethod" pointcut-ref="perform" throwing="ex"/>
                        
                        public void throwingMethod(Throwable ex){
                            System.out.println(ex.getMessage());
                        }
                        
                        // 目标类
                        public void savePerson(Person person) {
                            int i = 1/0;
                            sessionFactory.getCurrentSession().save(person);
                        }
                      -------------------------------------------------------------------------------
                  
                          
                          
             5、环绕通知
                  1、环绕通知可以控制目标方法的执行
                      方式: 在环绕通知中加一个参数:
                            org.aspectj.lang.JoinPoint包中的ProceedingJoinPoint joinPoint
                            然后在环绕通知中显示调用ProceedingJoinPoint的proceed()方法,,则执行目标方法
                  2、同时,各种通知若加JoinPoint参数(org.aspectj.lang.JoinPoint包),还可以获取目标方法的信息
                  例:
                      -------------------------------------------------------------------------------
                      不调用目标方法:
                          <aop:around method="aroundMethod" pointcut-ref="perform" />
                          
                          public void aroundMethod(){
                              System.out.println("around inform");  
                          }
                      
                          // 目标方法 注: 此时未调用目标方法
                          public String savePerson(Person person) {
                              System.out.println("目标方法");
                              return "返回值";
                          }
                      
                      
                      调用目标方法:
                          <aop:around method="aroundMethod" pointcut-ref="perform" />
                          
                          public void aroundMethod(ProceedingJoinPoint joinPoint) throws Throwable{
                              joinPoint.proceed(); // 显示的调用目标方法的执行,可以控制目标方法是否执行
                              System.out.println("around inform with targetMethod");
                              System.out.println("目标方法的方法名:"+joinPoint.getSignature().getName()); 
                          }
                          
                          // 目标方法: 注: 此时调用了目标方法
                          public String savePerson(Person person) {
                              System.out.println("目标方法");
                              return "返回值";
                          }
                      -------------------------------------------------------------------------------
       
       
       
       7、例1: 一个切面
            --------------------------------------------------------------------------------
                public class Person implements Serializable {
                    private Long pid;
                    private String pname;
                    private String psex;
                }
                
                // 接口
                public interface PersonDao {
                    public void savePerson(Person person);
                }
                
                // 目标类
                public class PersonDaoImpl extends HibernateUtil implements PersonDao {
                    @Override
                    public void savePerson(Person person) {
                        sessionFactory.getCurrentSession().save(person);
                    }
                }
                
                // 切面
                public class MyTransaction extends HibernateUtil{
                    private Transaction transaction;
                    // 通知
                    public void beginTransaction(){
                        this.transaction = sessionFactory.getCurrentSession().beginTransaction();      
                    }
                    // 通知
                    public void commit(){
                        this.transaction.commit();
                    }
                }
                
                配置文件:
                    <!-- AOP   导入目标类,导入切面 -->
                    <bean id="personDao" class="cn.itcast.spring.aop.PersonDaoImpl"></bean>
                    <bean id="myTransaction" class="cn.itcast.spring.aop.MyTransaction"></bean>
                    <!-- AOP 的配置 -->
                    <aop:config>
                      <!-- 切入点表达式 里面含有目标方法   -->
                      <aop:pointcut expression="execution(* cn.itcast.spring.aop.PersonDaoImpl.*(..))" id="perform"/>
                      <!-- 声明切面 -->
                      <aop:aspect ref="myTransaction">
                        <!-- 声明通知及其触发时间 -->
                        <aop:before method="beginTransaction" pointcut-ref="perform"/>
                        <aop:after-returning method="commit" pointcut-ref="perform"/>
                      </aop:aspect>
                    </aop:config>
                    
                测试:
                    public class PersonTest {
                      @Test
                      public void test(){
                          ApplicationContext context = new ClassPathXmlApplicationContext(
                                              "cn/itcast/spring/aop/applicationContext.xml");  
                          // 注: 此处得到的是代理对象                                         
                          PersonDao personDao = (PersonDao) context.getBean("personDao");
                          Person person = new Person();
                          person.setPname("aaa");
                          person.setPsex("男");
                          personDao.savePerson(person);
                      }
                    }


            --------------------------------------------------------------------------------
            
         例1: 多个切面
            --------------------------------------------------------------------------------
                目标类:
                    public class SalaryManagerImpl {
                        public void show(){
                            System.out.println("目标方法:查看工资");
                        }
                    }
                
                切面1:
                    public class Logger {
                        public void logger(){
                            System.out.println("logger");  
                        }
                    }
                
                切面2:    
                    public class Security {
                        public void security(){
                            System.out.println("security");
                        }
                    }
                    
                切面3:
                    public class Privilege {
                        private String access;
                        // set/get属性
                        
                        public void hasAccess(ProceedingJoinPoint joinPoint) throws Throwable{
                            if(this.access.equals("admin")){
                                joinPoint.proceed();
                            }else{
                                System.out.println("对不起,您没有权限");
                            }
                        }
                    }
                
                配置文件:
                    <bean id="salaryManager" class="cn.itcast.spring.aop.aspeces.SalaryManagerImpl"></bean>

                    <bean id="logger" class="cn.itcast.spring.aop.aspeces.Logger"></bean>
                    <bean id="security" class="cn.itcast.spring.aop.aspeces.Security"></bean>
                    <bean id="privilege" class="cn.itcast.spring.aop.aspeces.Privilege">
                        <property name="access" value="admin1"></property>
                    </bean>
                    
                    <aop:config>
                      <aop:pointcut expression="execution(
                                      * cn.itcast.spring.aop.aspeces.SalaryManagerImpl.*(..))" id="perform"/>
                      <aop:aspect ref="logger">
                          <aop:before method="logger" pointcut-ref="perform"/>
                      </aop:aspect>
                      <aop:aspect ref="security">
                          <aop:before method="security" pointcut-ref="perform"/>
                      </aop:aspect>
                      <aop:aspect ref="privilege">
                          <aop:around method="hasAccess" pointcut-ref="perform"/>
                      </aop:aspect>
                    </aop:config>
                
                测试:
                    public class SalaryTest {
                      @Test
                      public void test(){
                        ApplicationContext context = new ClassPathXmlApplicationContext("
                                          cn/itcast/spring/aop/aspeces/applicationContext.xml");          
                        SalaryManagerImpl proxy = (SalaryManagerImpl) context.getBean("salaryManager");
                        proxy.show();
                      }
                    }
            
            --------------------------------------------------------------------------------
       
       
        
      8、例:统一的错误异常处理
            --------------------------------------------------------------------------------
                public class PersonAction {
                    private PersonService personService = new PersonServiceImpl();
                    // set/get属性    
                    public String savePerson() throws Exception{
                        this.personService.savePerson();
                        return null;
                    }            
                }
                
                public interface PersonService {
                    public void savePerson() throws Exception;
                }
                
                public class PersonServiceImpl implements PersonService {
                    PersonDao personDao = new PersonDaoImpl();                    
                    // set/get属性
                    @Override
                    public void savePerson() throws Exception {
                      this.personDao.savePerson();
                      throw new RuntimeException("service层异常");    
                    }  
                }
                
                public interface PersonDao {
                    public void savePerson() throws Exception; 
                }
                
                public class PersonDaoImpl implements PersonDao {
                    @Override
                    public void savePerson() throws Exception{
                        System.out.println("save person daoImpl");
                        throw new RuntimeException("dao层异常");
                    }
                }          
                
                public class MyException {
                    public void myException(Throwable ex){
                        System.out.println(ex.getMessage());
                    }
                }
                
                配置文件:
                    <bean id="personDao" class="cn.itcast.dao.impl.PersonDaoImpl"></bean>
                    <bean id="personService" class="cn.itcast.service.impl.PersonServiceImpl">
                      <property name="personDao">
                        <ref bean="personDao"/>
                      </property>
                    </bean>
                    <bean id="personAction" class="cn.itcast.action.PersonAction">
                      <property name="personService">
                        <ref bean="personService"/>
                      </property>
                    </bean>
                    <bean id="myException" class="cn.itcast.myException.MyException"></bean>                    
                    
                    <aop:config>
                      <aop:pointcut expression="execution(* cn.itcast.service.impl.*.*(..))" id="perform"/>
                      <aop:aspect ref="myException">
                        <aop:after-throwing method="myException" pointcut-ref="perform" throwing="ex"/>
                      </aop:aspect>
                    </aop:config>

                测试:
                    public class UnionExceptionTest {
                        @Test
                        public void test() throws Exception {
                            ApplicationContext context = new ClassPathXmlApplicationContext("
                                                                applicationContext.xml");
                            PersonAction personAction = (PersonAction) context.getBean("personAction");
                            personAction.savePerson();
                        }                     
                    }
                
            --------------------------------------------------------------------------------
       
       
      9、 springAOP注解的形式
            --------------------------------------------------------------------------------
                public class Person implements Serializable {
                    private Long pid;
                    private String pname;
                    private String psex;
                    // set/get属性
                }
            
                public interface PersonDao {
                    public void savePerson(Person person);
                }
                
                @Repository("personDao")
                public class PersonDaoImpl extends HibernateUtil implements PersonDao {
                    @Override
                    public void savePerson(Person person) {
                        sessionFactory.getCurrentSession().save(person);
                    }
                }
                
                /**
                @Aspect相当于:
                  <aop:config></aop:config>
                */
                // 切面
                @Component("myTransaction")
                @Aspect
                public class MyTransaction extends HibernateUtil{
                    private Transaction transaction;
                    
                    /**
                    @Pointcut("execution(* cn.itcast.spring.aop.annotation.PersonDaoImpl.*(..))")相当于
                      <aop:pointcut expression="execution(* cn.itcast.spring.aop.annotation.PersonDaoImpl.*(..))" id="perform"/>            
                     */
                    @Pointcut("execution(* cn.itcast.spring.aop.annotation.PersonDaoImpl.*(..))")
                    private void perform(){}  // 方法签名,返回值必须是void,并且方法的修饰符最好是private
                    
                    // 前置通知  
                    /**
                    @Before("perform()")相当于:
                      <aop:before method="beginTransaction" pointcut-ref="perform"/>
                     */
                    @Before("perform()")
                    public void beginTransaction(){
                      this.transaction = sessionFactory.getCurrentSession().beginTransaction();      
                    }
                    
                    // 后置通知  
                    /**
                    @AfterReturning(value="perform()",returning="var")相当于:
                      <aop:after-returning method="commit" pointcut-ref="perform" returning="var"/>
                     */
                    @AfterReturning(value="perform()",returning="var")
                    public void commit(Object var){
                      this.transaction.commit();
                    }
                }
                
                配置文件:
                    <!-- 
                      把目标类和切面纳入到spring容器中管理,启动类扫描机制
                    -->
                    <context:component-scan base-package="cn.itcast.spring.aop.annotation"/>
                    
                    <!-- 启动AOP的注解解析器  然后再在切面中写注解来代替配置信息  -->
                    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
                
                测试:
                    public class PersonTest {
                        @Test
                        public void test(){
                              ApplicationContext context = new ClassPathXmlApplicationContext("
                                      cn/itcast/spring/aop/annotation/applicationContext.xml");                       
                              PersonDao personDao = (PersonDao) context.getBean("personDao");
                              Person person = new Person();
                              person.setPname("bbb");
                              person.setPsex("男");
                              personDao.savePerson(person);
                        }
                    }
                
            --------------------------------------------------------------------------------
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
       
0 0
原创粉丝点击