zoukankan      html  css  js  c++  java
  • Spring Aop面向切面编程&&自动注入

    1.面向切面编程

      在程序原有纵向执行流程中,针对某一个或某一些方法添加通知,形成横切面的过程叫做面向切面编程

    2.常用概念

      原有功能:切点,pointcut

      前置通知:在切点之前执行的功能,before advice

      后置通知:在切点之后执行的功能,after advice

      如果切点执行过程中出现异常,会触发异常通知,throws advice

      所有功能的总称叫做切面

      织入:把切面嵌入原有功能的过程叫做织入

    3.Schema-based方式

      每个通知都需要实现接口或类

      配置spring配置文件时在<aop:config>配置

    4.AspectJ方式

      每个通知不需要实现接口或类

      配置spring配置文件时在<aop:config>的子标签<aop:aspect>中配置

    5.Schema-based

    Demo.java

    public class Demo {
        public void demo1(){
            System.out.println("demo1");
        }
        public void demo2(){
            System.out.println("demo2");
        }
        public void demo3(){
            System.out.println("demo3");
        }
    }

      (1)导入jar包

        aopalliance-1.0.jar

        aspectjweaver-1.9.2.jar

      (2)新建前置通知类

      arg0:切点方法对象Method对象

      arg1:切点方法参数

      arg2:切点方法所在类的对象

    public class MyBeforeAdvice implements MethodBeforeAdvice{
        
        @Override
        public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
            System.out.println("执行前置通知");
        }
    }

      (3)新建后置通知类

      arg0:切点方法返回值

      arg1:切点方法对象Method对象

      arg2:切点方法参数

      arg3:切点方法所在类的对象

    public class MyAfterAdvice implements AfterReturningAdvice {
    
        @Override
        public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable {
            System.out.println("执行后置通知");
        }
    }

      (4)配置spring配置文件

    <?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"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
                http://www.springframework.org/schema/beans/spring-beans.xsd
                http://www.springframework.org/schema/aop
                http://www.springframework.org/schema/aop/spring-aop.xsd">
        <!-- 配置通知类的对象,在切面中引入 -->        
        <bean id="mybefore" class="com.mxj.advice.MyBeforeAdvice"></bean>        
        <bean id="myafter" class="com.mxj.advice.MyAfterAdvice"></bean>
        <!-- 配置切面 -->
        <aop:config>
            <!-- 配置切点 *通配符:匹配任意方法名,任意类名,任意一级包名;(..):任意类型参数-->
            <aop:pointcut expression="execution(* com.mxj.test.Demo.demo2())" id="mypoint"/>
            <!-- 通知 -->
            <aop:advisor advice-ref="mybefore" pointcut-ref="mypoint"/>
            <aop:advisor advice-ref="myafter" pointcut-ref="mypoint"/>
        </aop:config>
        <!-- 配置Demo类 -->
        <bean id="demo" class="com.mxj.test.Demo"></bean>
    </beans>

     6.配置异常通知的步骤(AspectJ方式)

      (1)只有切点报异常才能触发异常通知

      (2)在spring中只有AspectJ方式提供了异常通知的方法

      (3)实现步骤

    新建类,在类中写任意名称的方法

    public class MyThrowAdvice {
        public void myexception(){
            System.out.println("执行异常通知");
        }
    }

    在spring配置文件中配置

      <aop:aspect>的ref属性表示:方法在哪个类中

      <aop:xxxx/>表示xxx通知

      method:当触发这个通知时调用哪个方法

      throwing:异常对象名,必须和通知中方法参数名相同(可以不在通知中声明异常对象)

      <bean id="mythrow" class="com.mxj.advice.MyThrowAdvice"></bean>
        <aop:config>
            <aop:aspect ref="mythrow">
                <aop:pointcut expression="execution(* com.mxj.test.Demo.demo1())" id="mypoint"/>
                <aop:after-throwing method="myexception()" pointcut-ref="mypoint" throwing="e"/>
            </aop:aspect>
        </aop:config>
        <bean id="demo" class="com.mxj.test.Demo"></bean>

    7.异常通知(Schema-based方式)

       (1)新建一个类实现throwsAdvice接口

    public class MyThrow implements ThrowsAdvice{
        public void afterThrowing(Exception ex) throws Throwable {
           System.out.println("执行异常通知:schema-base方式");
        }
    }

      (2)配置applicationContext.xml

     <bean id="mythrow" class="com.mxj.advice.MyThrow"></bean>
       <aop:config>
           <aop:pointcut expression="execution(* com.mxj.test.Demo.demo1())" id="mypoint"/>
           <aop:advisor advice-ref="mythrow" pointcut-ref="mypoint"/>
       </aop:config>
        <bean id="demo" class="com.mxj.test.Demo"></bean>

    8.环绕通知(Schema-based方式)

      把前置通知和后置通知都写到一个通知中,就组成了环绕通知

      (1)新建一个类实现 MethodInterceptor(拦截器)

    public class MyArround implements MethodInterceptor{
        @Override
        public Object invoke(MethodInvocation arg0) throws Throwable {
            System.out.println("环绕-前置");
            Object result = arg0.proceed();
            System.out.println("环绕-后置");
            return result;
        }
    }

      (2)配置applicationContext.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"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
                http://www.springframework.org/schema/beans/spring-beans.xsd
                http://www.springframework.org/schema/aop
                http://www.springframework.org/schema/aop/spring-aop.xsd">
       <!-- 异常通知 -->
      <!--  <bean id="mythrow" class="com.mxj.advice.MyThrow"></bean>
       <aop:config>
           <aop:pointcut expression="execution(* com.mxj.test.Demo.demo1())" id="mypoint"/>
           <aop:advisor advice-ref="mythrow" pointcut-ref="mypoint"/>
       </aop:config>
        <bean id="demo" class="com.mxj.test.Demo"></bean> -->
    
        <bean id="myarround" class="com.mxj.advice.MyArround"></bean>
        <aop:config>
               <aop:pointcut expression="execution(* com.mxj.test.Demo.demo1())" id="mypoint"/>
               <aop:advisor advice-ref="myarround" pointcut-ref="mypoint"/>
       </aop:config>
       <bean id="demo" class="com.mxj.test.Demo"></bean>
    </beans>

     9.AspectJ方式实现

    类中方法名任意

    public class MyAdvice {
        public void mybefore(){
            System.out.println("前置");
        }
        public void myafter(){
            System.out.println("后置1");
        }
        public void myaftering(){
            System.out.println("后置2");
        }
        public void mythrow(){
            System.out.println("异常");
        }
        public Object myarround(ProceedingJoinPoint p) throws Throwable{
            System.out.println("执行环绕");
            System.out.println("环绕-前置");
            Object result = p.proceed();
            System.out.println("环绕-后置");
            return result;
        }
    }

    配置spring配置文件

      <aop:after/> 后置通知,是否出现异常都执行

      <aop:after-returning/> 后置通知,只有当切点正确执行时执行

      <aop:after/>、<aop:after-returning/>、<aop:after-throwing/>执行顺序和配置顺序有关

    <?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"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
                http://www.springframework.org/schema/beans/spring-beans.xsd
                http://www.springframework.org/schema/aop
                http://www.springframework.org/schema/aop/spring-aop.xsd">
        <bean id="demo" class="com.mxj.test.Demo"></bean> 
        <bean id="myadvice" class="com.mxj.advice.MyAdvice"></bean>
        <aop:config>
            <aop:aspect ref="myadvice">
            <aop:pointcut expression="execution(* com.mxj.test.Demo.demo1())" id="mypoint"/>
                <aop:before method="mybefore" pointcut-ref="mypoint"/>
                <aop:after method="myafter" pointcut-ref="mypoint"/>
                <aop:after-returning method="myaftering" pointcut-ref="mypoint"/>
                <aop:after-throwing method="mythrow" pointcut-ref="mypoint"/>
                <aop:around method="myarround" pointcut-ref="mypoint"/>
            </aop:aspect>
        </aop:config>
    </beans>

     10.AspectJ方式在通知中获取切点参数

    public class MyAdvice {
        public void mybefore(String name,int age){
            System.out.println("前置"+name+" "+age);
        }
    }

    配置文件

      <bean id="demo" class="com.mxj.test.Demo"></bean> 
        <bean id="myadvice" class="com.mxj.advice.MyAdvice"></bean>
        <aop:config>
            <aop:aspect ref="myadvice">
            <aop:pointcut expression="execution(* com.mxj.test.Demo.demo1(String,int)) and args(name,age)" id="mypoint"/>
                <aop:before method="mybefore" pointcut-ref="mypoint" arg-names="name,age"/>
            </aop:aspect>
        </aop:config>

     11.使用注解配置AOP(基于Aspect)

      spring不会自动寻找注解,必须告诉spring哪些包下类可能有注解

      (1)引入xmlns:context

      (2)@Component

          相当于<bean/>标签

          如果没有参数,把类名首字母变小写,相当于<bean id=""/>

          @Component("自定义名称")

      (3)实现步骤

        在spring文件中设置注解在哪些包中

     <context:component-scan base-package="com.mxj.advice,com.mxj.test"></context:component-scan>     
     <!-- 
      proxy-target-class true:使用cglib动态代理 false:使用jdk动态代理
    --> <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>

        在Demo类中添加@Componet

        在方法上添加@Pointcut("")定义切点

    @Component
    public class Demo { 
        @Pointcut("execution(* com.mxj.test.Demo.demo1())")
        public void demo1() throws Exception{
            System.out.println("demo1");
        }
    }

        在通知类中配置

          @Component类被spring管理

          @Aspect 相当于<aop:aspect/>表示通知方法在当前类中

    @Component
    @Aspect
    public class MyAdvice {
        
        @Before("com.mxj.test.Demo.demo1()")
        public void mybefore(){
            System.out.println("前置");
        }
        
        @After("com.mxj.test.Demo.demo1()")
        public void myafter(){
            System.out.println("后置");
        }
        
        @AfterThrowing("com.mxj.test.Demo.demo1()")
        public void mythrow(){
            System.out.println("异常通知");
        }
        
        @Around("com.mxj.test.Demo.demo1()")
        public Object myarround(ProceedingJoinPoint p) throws Throwable{
            System.out.println("环绕-前置");
            Object result = p.proceed();
            System.out.println("环绕-后置");
            return result;
        }
    }

     12.自动注入

      在Spring配置文件中对象名和ref="id" id名相同使用自动注入,可以不配置<property/>

      两种配置方法:

      (1)在<bean>中通过autowire=""配置,只对<bean>生效

      (2)在<beans>中通过default-autowire=""配置,表示当前文件中所有的<bean>都走全局配置

      (3)autowire=""可取值

        default:默认值,根据全局default-autowire=""值,默认全局和局部都没有配置情况下,相当于no

        no:不自动注入

        byName:通过名称自动注入,在Spring容器中找类的id

        byType:根据类型注入

          spring容器中不可以出现两个相同类型的<bean>

        constructor:根据构造方法注入

          提供对应参数的构造方法(构造方法参数中包含注入对象)

          底层使用byName,构造方法参数名和其他<bean>的id相同

    13.Spring中加载properties文件

      (1)在src下新建xxx.properties文件

      (2)在spring配置文件中先引入xmlns:context

          如果需要记载多个文件逗号分割

    <context:property-placeholder location="classpath:db.properties"/>

      (3)添加属性文件加载,在<beans>中开启自动注入需要注意的地方:

        SqlSessionFactoryBean的id不能叫做sqlSessionFactory

        修改:把原来通过ref引用替换成value赋值,自动注入只能影响ref,不会影响value赋值

    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.mxj.mapper"></property>
        <property name="sqlSessionFactoryBeanName" value="factory"></property>
    </bean>

     14.Spring加载属性文件

      在被Spring管理的类中通过@Value("{key}")取出properties中内容

      (1)添加注解扫描

    <context:component-scan base-package="com.mxj.service.impl"></context:component-scan>

      (2)在类中添加

        key和变量名可以不相同

        变量类型任意,只要保证key对应的value能转换成这个类型就可以

    @Value("${my.demo}")
    private String test;

     15.scope属性

      (1)<bean>的属性

      (2)作用:控制对象有效范围(单例,多例等)

      (3)<bean/>标签对应的对象默认是单例的,无论获取多少次都是一个对象

      (4)scope可取值

        singleton:默认值,单例

        prototype: 多例,每次获取重新实例化

        request: 每次请求重新实例化

        session:每个会话对象内,对象是单例的

        application:在application对象内是单例

        global session spring推出一个对象,依赖于spring-webmvc-portlet,类似于session

          

  • 相关阅读:
    STM32的“外部中断”和“事件”区别和理解
    非线性函数的最小二乘拟合——兼论Jupyter notebook中使用公式 [原创]
    Jupyter 快捷键总结
    自制导纳信号发生器 [原创cnblogs.com/helesheng]
    Verilog HDL数组(存储器)操作
    一个有趣的异步时序逻辑电路设计实例 ——MFM调制模块设计笔记
    用NI的数据采集卡实现简单电子测试之6——数字I/O及测试平台
    用NI的数据采集卡实现简单电子测试之5——压控振荡器的测试
    用NI的数据采集卡实现简单电子测试之4——半导体温度传感器
    黑客用我们服务器挖矿了
  • 原文地址:https://www.cnblogs.com/mxj961116/p/11265517.html
Copyright © 2011-2022 走看看