zoukankan      html  css  js  c++  java
  • Spring AOP(面向切面示例)

    什么是AOP?
    基本概念
    切面(aspect):横切关注点被模块化的特殊对象。
    通知(advice):切面必须要完成的工作。切面中的每个方向称之为通知。通知是在切面对象中的。
    目标(target):被通知的对象。
    代理(proxy):向目标对象应用通知后创建的对象。

    连接点(joinpoint):目标对象的程序执行的某个特定位置。如某个方法调用前,调用后的位置。包括两个信息:1.目标程序的哪个方法?2.方法执行 
    前还是执行后?
    切点(pointcut):每个类会有多个连接点,AOP通过切点定位到特定的边接点。
    类比,连接点相当于数所成方圆 中的记录,而切点相当于查询条件。一个切点匹配多个连接点。

    使用XML配置的方法:

    1.导入 spring包和aspectj的两个jar包

    2.目标对象(要切入的对象)

    首先为了不违反开闭原则和更好的可扩展性,目标对象实际上是实现了已定义好的某个接口

    接口:

    package com.itnba.test;
    
    public interface IHuman {
        public void chifan();
        public void shuijiao();
    
    }

    实现接口的两个类:

    package com.itnba.test;
    
    import org.springframework.stereotype.Component;
    
    public class Chinese implements IHuman {
    
        @Override
        public void chifan() {
            // TODO 自动生成的方法存根
            System.out.println("中国人吃饭");
    
        }
        
        @Override
        public void shuijiao() {
            // TODO 自动生成的方法存根
            System.out.println("中国人睡觉");
        }
    
    }
    package com.itnba.test;
    
    import org.springframework.stereotype.Component;
    
    
    public class American implements IHuman {
    
        @Override
        public void chifan() {
            // TODO 自动生成的方法存根
            System.out.println("美国人吃饭");
    
        }
    
        @Override
        public void shuijiao() {
            // TODO 自动生成的方法存根
            System.out.println("美国人睡觉");
        }
    
    
    }

    3.定义一个切面类

    package com.itnba.test;
    
    import org.aspectj.lang.annotation.After;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.springframework.stereotype.Component;
    public class Qiemian {
        
        public void chifanqian(){
            System.out.println("洗手");
        }
        public void chifanhou(){
            System.out.println("漱口");
        }
        public void shuijiaoqian(){
            System.out.println("洗澡");
            
        }
    
    }

    4.XML文件配置

    <?xml version="1.0" encoding="UTF-8"?>
    <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"
        xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="http://www.springframework.org/schema/beans 
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context 
            http://www.springframework.org/schema/context/spring-context-4.3.xsd
            http://www.springframework.org/schema/aop 
            http://www.springframework.org/schema/aop/spring-aop-4.3.xsd"
            default-autowire="byName"
            >
             <!-- 首相要实例化目标对象类和切面类 -->
            <bean id="chinese" class="com.itnba.test.Chinese"></bean>
            <bean id="american" class="com.itnba.test.American"></bean>
            <bean id="qiemian" class="com.itnba.test.Qiemian"></bean>
            
            <aop:config>
            <!-- 要切入的对象 -->                 
            <aop:pointcut expression="execution(* com.itnba.test.*.chifan(..))" id="chifan"/>
            <aop:pointcut expression="execution(* com.itnba.test.*.shijiao(..))" id="shijiao"/>
            <!-- 切入点 -->
            <aop:aspect id="ha" ref="qiemian"><!-- 切面类  -->
                <!--  <aop:之前before、之后after... method="切面类中的方法" pointcut-ref="上面的切入的对象"/>  -->
                <aop:before method="chifanqian()" pointcut-ref="chifan"/><!-- 之前通知 -->
                <aop:after method="chifanhou()()" pointcut-ref="chifan"/><!-- 之后通知 -->
                <aop:before method="shuijiaoqian()" pointcut-ref="shijiao"/>
            </aop:aspect>
        </aop:config>
    </beans>

    5.运行

    package com.itnba.test;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class Test {
    
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
            //要用接口接收
            IHuman c= (IHuman)context.getBean("chinese");
            c.chifan();
            c.shuijiao();
            System.out.println("*********************************");
            //要用接口接收
            IHuman a= (IHuman) context.getBean("american");
            a.chifan();
            a.shuijiao();
    
        }
    
    }

    结果:

     

    使用注解的方法:

    1.导如 spring包和aspectj的两个jar包


    2.配置文件中加入aop命名空间

    <?xml version="1.0" encoding="UTF-8"?>
    <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"
        xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="http://www.springframework.org/schema/beans 
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context 
            http://www.springframework.org/schema/context/spring-context-4.3.xsd
            http://www.springframework.org/schema/aop 
            http://www.springframework.org/schema/aop/spring-aop-4.3.xsd" >
    
            <!-- 自动扫描包下的类,并将其实例化。多个包之间用,隔开 -->
            <context:component-scan base-package="com.itnba.test"></context:component-scan>
            <!-- 配置文件中启动AspectJ的注解功能 ,默认是false,要将其改为true -->
            <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy> 
    </beans>

    3.目标对象(要切入的对象)

    首先为了不违反开闭原则和更好的可扩展性,目标对象实际上是实现了已定义好的某个接口

    接口:

    package com.itnba.test;
    
    public interface IHuman {
        public void chifan();
        public void shuijiao();
    
    }

    实现接口的两个类:

    package com.itnba.test;
    
    import org.springframework.stereotype.Component;
    
    @Component
    public class Chinese implements IHuman {
    
        @Override
        public void chifan() {
            // TODO 自动生成的方法存根
            System.out.println("中国人吃饭");
    
        }
        
        @Override
        public void shuijiao() {
            // TODO 自动生成的方法存根
            System.out.println("中国人睡觉");
        }
    
    }
    package com.itnba.test;
    
    import org.springframework.stereotype.Component;
    
    @Component
    public class American implements IHuman {
    
        @Override
        public void chifan() {
            // TODO 自动生成的方法存根
            System.out.println("美国人吃饭");
    
        }
    
        @Override
        public void shuijiao() {
            // TODO 自动生成的方法存根
            System.out.println("美国人睡觉");
        }
    
    
    }

    4.定义一个切面类,直接在里面注解

    package com.itnba.test;
    
    import org.aspectj.lang.annotation.After;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.springframework.stereotype.Component;
    @Aspect //声明该类是切面类
    @Component//配置文件中启动自动扫描功能
    public class Qiemian {
        
        @Before("execution(* com.itnba.test.*.chifan(..))")//在那个方法的之前通知    *代表全部..代表所有形参,不管有多少
        public void chifanqian(){
            System.out.println("洗手");
        }
        @After("execution(* com.itnba.test.*.chifan(..))")//在那个方法之后通知
        public void chifanhou(){
            System.out.println("漱口");
        }
        @Before("execution(* com.itnba.test.*.shuijiao(..))")
        public void shuijiaoqian(){
            System.out.println("洗澡");
            
        }
    
    }

    5.写好后用main函数来运行一下

    package com.itnba.test;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class Test {
    
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
            Chinese c= context.getBean(Chinese.class);
            c.chifan();
            c.shuijiao();
            System.out.println("*********************************");
            American a= (American) context.getBean("american");
            a.chifan();
            a.shuijiao();
    
        }
    
    }

    结果:

    这样,Spring的面向切面编程就简单介绍完了。

    通知分类:
    前置通知(@Before) -- 在目标方法执行前执行的通知。
    后置通知(@After) -- 在目标方法执行后执行的通知。无论是否发生异常。后置通知中,无法读取目标方法返回的结果。
    返回通知(@AfterReturnning) --在目标方法执行成功后执行的通知。在返回通知中可以访问目标返回结果的。 
    @AfterReturnning(value="execution(* com.itnba..*(..))",returning="result")
    public void afterRun(Object result){
    System.out.println(result);
    }

    异常通知(@AfterThrowing) -- 在目标方法执行出错后执行的通知。
    @AfterThrowing(value="execution(* com.itnba..*(..))",throwing="ex")
    public void afterThrowing(Exception ex){
    System.out.println(ex.getMessage());
    }

    环绕通知(@Around) -- 需要切面方法携带ProceedingJoinPoion参数,类似于一个完整的动态代理,环绕通知必须要有一个返回值,是目标方法的返 
    回值。

    @Around("execution(* com.itnba..*(..))")
    public object aroundAdvice( ProceedingJoinPoint pjp){

    object obj = null;
    try{
    //做前置通知
    obj = pjp.proceed();
    //做返回通知
    }
    catch(Exception ex){
    //做异常通知
    }
    //做后置通知
    return obj;
    }

    添加日志:

    切面方法可以加入参数(JoinPoint) joinPost.getSignature().getXXX()获得相关方法信息
    切面方法中可以加入Object参数,用来获得目标方法的返回值(只对返回通知起作用)

  • 相关阅读:
    出版文字作品报酬规定(收藏)
    关于Delphi7 的XML说明
    我做的XML验证的测试记录
    印刷常用名词
    验证XLM数据合法性(收藏)
    关于.Net操作XML相关类
    我的性格
    webpack学习笔记一
    汇编语言内存变量的地址
    Linux 汇编语言(GNU GAS汇编)开发指南
  • 原文地址:https://www.cnblogs.com/hq233/p/6637488.html
Copyright © 2011-2022 走看看