上篇博客我們系統的聊了《JavaEE開發之基於Eclipse的環境搭建以及Maven Web App的創建》,並在之前的博客中我們聊了依賴注入的相關東西,並且使用Objective-C的Runtime來實現了ObjC中的依賴注入,相關博客請參考《類比Spring框架來實現OC中的依賴注入》。當然之前的博客也是使用了ObjC的Runtime的東西來實現了ObjC中的“面向切面”編程的實現方式,相關博客請移步於《ObjC中的AOP--面向切面編程》。本篇博客我們就來看一下Spring框架中的依賴注入以及AOP編程的幾種方式,當然其實現方式是使用了Java的“反射機制”,也就類似於ObjC中的Runtime了。
今天博客中所使用的Spring版本是4.3.6.RELEASE,是目前比較新的Spring版本了。而Java的版本使用的是Java8了。上篇博客我們主要聊了相關環境的創建與配置,本篇博客將不會對環境配置這些東西進行詳細的敘述。本篇博客主要聊了Spring框架中的依賴注入的實現方式,主要是通過注解以及Java配置來實現的,當然還會聊些AOP的東西。
一、快速創建Mava管理的Spring工程
因為本篇博客是討論關於Spring的東西,所以我們就不創建WebApp的工程了。我們使用Spring來快速的創建一個Maven管理的工程。如下所示找到File->New->Maven Project選項來創建一個新的Maven Project,具體如下所示:
下方我們選擇創建一個簡單的Maven工程,跳過模板的選擇。上篇博客我們在創建Maven工程時,是沒有選擇下方這個選項的,然后我們選擇了一個WebApp的模板。而本篇博客,我們不需要WebApp的模板,只需要一個簡單的Maven工程即可。
接着輸入組織名和工程名,如下所示。點擊Finish即可完成Maven簡單工程的創建。
下面就是我們創建好的Maven 工程的目錄結構,我們的工程代碼要放在src/main/java中,稍后會使用到。
創建好上述工程后,我們要在pom.xml中引入我們的Spring依賴包。下方xml就是pom.xml中的內容。我們先引入了spring-context包,如下所示:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.zeluli</groupId> <artifactId>SpringDemoWithMaven</artifactId> <version>0.0.1-SNAPSHOT</version> <properties> <java.version>1.8</java.version> <spring.version>4.3.6.RELEASE</spring.version> </properties> <dependencies> <!-- Spring 核心包的引入 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-complier-plugin</artifactId> <version>3.3.9</version> <configuration> <source>${java.version}</source> <target>${java.version}</target> </configuration> </plugin> </plugins> </build> </project>
二、Spring中的依賴注入
接下來我們要來看一下Spring中的依賴注入的調用方式,該部分主要聊了兩種Spring中的依賴注入的方式。一種是注解方式,這種方式也是常用的,另一種就是Java配置類的方式。當然在早期Spring版本中是使用xml進行依賴注入的,因為xml配置的繁瑣以及不方便管理的一些特點,所以我們在工程中一般使用注解以及Java配置的形式。下方會給出注解以及Java配置的形式,並給出其使用場景。
1、使用注解實現依賴注入
本小部分,我們將使用注解來聲明Spring中的Bean。主要是使用@Service注解來聲明業務邏輯層(Service層)所使用的Bean,使用@Repository注解聲明數據訪問層(DAO層)使用的Bean,使用@Controller注解來聲明展現層的Bean,使用@Component來注解組件的Bean。當然這幾個注解其在底層的實現是大同小異的,其功能也是類似的,只是名稱不同。
我們可以使用Spring提供的@Autowired來聲明依賴注入的注入點,也可以使用JSR-330提供的@Inject或者JSR-250提供的@Resource注解聲明注入點。下面就來看一下這些注解的使用方式。
(1) @Repository
下方代碼片段就是使用@Repository注解來聲明的Bean,在數據訪問層會使用該注解來聲明DAO層的Bean。稍后我們會使用到下方的RepositoryBean。
(2) @Service
下方是我們使用@Service來聲明的Bean,在業務邏輯層,我們會使用到@Service注解進行Bean的聲明。在下方代碼段中,我們使用@Service聲明ServiceBean后,在該類中,我們注入了RepositoryBean的對象。當然使用的是@Autowired來注解的依賴對象的注入點。也就是說,在運行時,會動態的給下方的repositoryBean分配一個RepositoryBean的對象。如下所示:
(3) @Component
@Component是用來聲明組件的,也就是說你封裝了一個組件,這個組件就是使用@Component來進行注解,使其可以被注入。下方就是使用了@Component注解聲明的組件。稍后我們會在Controller中進行調用。
(4) @Controller
接下來我們就使用@Controller來聲明我們的控制器,下方的ControllerBean就是我們的控制器類,當然此處我們使用@Controller進行的注解。然后在該控制器類中,我們使用了@Autowired注解來注入ServiceBean和ComponentBean的對象,然后在下方相應的方法中進行了使用。
(5)、創建Spring的配置文件
接下來我們將創建Spring的配置文件,因為Spring可以通過此配置文件讀取一些上下文的信息。當然,Spring的配置文件其實就是一個Java類,然后我們使用@Configuration進行修飾即可。而@ComponentScan("包名")負責指定組件所在的包,也就是說設置完該項后,Spring會自動掃描該包下的@Component、@Service、@Repository、@Controller這些注解。
(6)、創建Main函數進行測試
上面一些列的Bean已經創建完畢,接下來,我們要創建我們測試用的Main函數了。首先我們使用注解配置上下文AnnotationConfigApplicationContext對象來從Java的配置文件中獲取Spring的上下文。然后獲取Controller Bean,下方是調用Controller Bean的相應的方法。最后再將調用的資源關閉掉即可。
(7)、運行結果
上述實現完Main方法后,接下來我們就可以對其運行並看起運行效果了。具體運行結果如下所示:
2、Java配置
上面一部分是使用Spring中提供的相關注解來聲明的各種類型的Bean。接下來我們就在Spring的配置文件來聲明相關的Bean,當然在Java配置文件中聲明的Bean一般是全局的,也就是說一些Bean要定義成全局的對象的話,我們就在Java配置中來進行Bean的聲明。例如一些公共的組件的Bean,我們就可以將其放入到Java的配置文件中。接下來我們就來看一下Spring配置文件中是如何來聲明Bean的。
(1)、創建Java配置使用的類
首先我們來創建一個類,此處我們命名為JavaConfigBean。然后我們要在Spring的配置文件中將其聲明為Bean。我們可以看出,下方類就是一個普通的Java類,該類中並沒有使用任何的注解進行修飾。
(2)、在Spring配置文件中聲明Bean
接下來我們將會在Spring的配置文件中使用@Bean注解將上述的JavaConfigBean聲明為Bean對象。下方代碼段就是Spring配置文件中的內容,其中的createJavaConfigBean()方法負責生成上述類的對象。其中我們使用@Bean注解聲明該方法,該方法會返回JavaConfigBean類的對象。在使用JavaConfigBean的對象時,會將下方生成的對象注入到相應的點上。
(3)、創建依賴JavaConfigBean的Controller
接下來我們就來創建一個Controller類,在該類中我們來使用JavaConfigBean的對象。下方就是我們創建的ControllerBean的類中的具體內容,其中使用了@Autowired注解來聲明的注入點,如下所示:
(4)、創建Main函數以及測試結果
接下來我們就該創建一個Main函數來進行測試了。在Main函數中依然是調用了ControllerBean的相關方法,如下所示:
三、面向切面編程--(Aspect Oriented Programming)
在前段時間發布的博客中,我們已經使用了ObjC的Runtime來演示了AOP編程的實現原理。在Java中利用了Java的“反射機制”來實現的。其實在運行時,我們通過方法體的交換就可以實現AOP編程。Spring中的AOP編程也不例外,也是通過方法交換來實現的,本篇博客,我們就來看一下Spring框架中是如何使用AOP編程的。本部分給出了Spring框架中兩種AOP編程的調用方案,一種是基於注解式的攔截方式,另一種是基於方法式的攔截。
下方將會分別給出這兩種AOP編程實現的兩種方式。在基於注解式的攔截方式中,我們需要為切點方法添加注解,而方法式攔截則不需要在切點方法上做任何操作。
1、引入Spring的AOP依賴包和AspectJ依賴包
下方的XML內容就是我們要在pom.xml添加的相關依賴配置,下方我們添加了spring-aop以及aspectj的依賴。aspectj也是一個Java的面向切面編程的依賴包。我們要做的東西也依賴於aspectj。具體的依賴包的引入如下所示:
<!-- spring aop支持 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>4.3.6.RELEASE</version> </dependency> <!-- aspectj支持 --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.8.9</version> </dependency>
2、基於注解的AOP
接下來我們將實現基於注解式的AOP實現,下方我們將創建AOP使用的注解,切面類、被切面的Controller、Spring配置文件以及測試用的Main函數。下方是基於注解的AOP的具體實現。
(1)、創建AOP使用的注解
首先我們先創建一個注解,該注解會在切入點中進行使用。選擇我們相應的package,然后右鍵單擊->New->Annotation來創建一個注解。
該注解中的內容比較簡單,具體內容如下所示:
package com.zeluli.aop.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Action { }
(2)、創建切面切入的Controller
接下來我們就來創建一個切面切入的Controller,此處我們將該類命名為AnnotationController。在該Controller中相應方法上,我們使用上述我們創建的@Action注解來進行聲明,將其聲明為我們切面的切入點。具體如下所示:
(3)、編寫切面類
定義好聲明切點的注解@Action以及被切入的Controller后,接下來,我們就該創建切面類了。下方創建的LogAspect類就是用來切入AnnotationController類的切面類。具體內容如下所示。
我們使用@Aspect注解將LogAspect類聲明為切面,然后使用@Component注解將其聲明為組件。之所以將其聲明為組件,是因為我們可以將該切面切入到好多類中。然后我們使用@Pointcut注解來指定切入點,@Pointcut參數就是我們上面創建的注解@Action。也就是說使用@Action修飾的方法就是我們的切入點。使用@Before注解來聲明在切點之前執行的方法,使用@After注解來聲明在切點之后執行的方法。下方就是LogAspect類的具體內容。
(4)、創建Spring的配置文件
接着我們要創建配置類,在配置類中我們要開啟AspectJ的自動代理,如下所示。
(5)、創建Main函數進行測試
接下來,我們就開始測試了。Main方法比較簡單,與上面的Main方法大同小異。主要是調用AnnotationConfigApplicationContext來從配置文件中加載上下文,然后根據上下文獲取AnnotationController的對象,然后調用testMethod()方法,最后將上下文進行關閉即可。
public class Main { public static void main(String[] args) { AnnotationConfigApplicationContext aopContext = new AnnotationConfigApplicationContext(AopConfig.class); AnnotationController controller = aopContext.getBean(AnnotationController.class); controller.testMethod(); aopContext.close(); } }
下方截圖就是上述Main方法的運行結果,可見,在testMethod()方法調用之前會執行切片的@Before方法,testMethod()方法執行之后會執行@After方法。具體結果如下所示:
3、基於方法的AOP
上面我們聊了基於注解攔截的切面,接下來我們就來看一下基於方法的切面。也就是說在該部分,我們不會創建注解。直接創建LogAspect切面即可。下方這個LogAspect切面就是基於方法的切面。其中在@Before或者@After注解后邊跟着一串字符串,該字符串就是切入點所在類。如下所示。
上述切面的運行效果與注解切面的運行效果一致,在此就不做過多贅述了。
本篇博客就先到此,上述相關代碼在github上的分享地址為:https://github.com/lizelu/SpringDemo