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

      


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM