1.Spring IOC IOC技術: 控制反轉,也叫(依賴註入) 控制反轉:Bean的生命周期不受你控制,而是交給Spring容器管理。 Spring框架如何利用IOC ?: 實現了控制反轉,Spring容器能幫我們實例化對象,但是並沒有做到DI(依賴註入)。 作用: (1) 構建Bean (2) ...
1.Spring IOC
IOC技術: 控制反轉,也叫(依賴註入)
控制反轉:Bean的生命周期不受你控制,而是交給Spring容器管理。
Spring框架如何利用IOC ?:
實現了控制反轉,Spring容器能幫我們實例化對象,但是並沒有做到DI(依賴註入)。
作用:
(1) 構建Bean
(2) Bean之間有依賴關係的話,可以自動幫我們註入
優勢:
解耦:低耦合,實現面向介面的編程思想
2.Spring AOP
動態代理設計模式
原理和靜態代理設計模式沒有本質區別:
被代理類、代理類、被代理和代理類是同一個介面
代理類的創建過程有區別:
(1)靜態代理:
自己編寫代理類,代理類自己實現介面
(2)動態代理:
代理類不需要自己編寫,他Proxy.newProxyinstance(xx)靜態方法
在程式執行過程中,動態產生代理類
InvocationHandler:裡邊含有被代理類的引用
AOP:面向切麵的編程
代理模式主要的作用:
在業務代碼不之情的情況下,切入額外的功能。
原理:Spring框架具有IOC的功能,所以我們可以利用該功能配置業務Bean 。代理設計模式(動態)
例如: AccountServiceImpl
<bean id="AccountServiceImpl" class="service.AccountServiceImpl"></bean>
然後,Spring框架利用動態代理設計模式創建一個AccountServiceImpl的動態代理對象
然後就可以在AccountServiceImpl的業務方法的基礎上增加相應的功能。
那Spring把這種技術稱為AOP面向切麵的編程,其實就是在程式員不知情的情況下在其業務方法上切入額外的功能。
使用 XML 配置實現具體的操作:
(1)使用Spring的AOP功能,就需要引入jar pom.xml
(2)自己編寫切麵。很類似於InvocationHandler
被代理介面 : 業務介面
被代理類: 實現了被代理口,被代理類也叫業務實現類;
例子:class CalFfabImpl implements ICalFab
代碼示例:
Maven項目
pom.xml 添加的插件
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjrt --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.8.10</version> </dependency> <!-- https://mvnrepository.com/artifact/aopalliance/aopalliance --> <dependency> <groupId>aopalliance</groupId> <artifactId>aopalliance</artifactId> <version>1.0</version> </dependency> <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjrt --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.10</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-aop --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${spring.version}</version> </dependency>
添加資源配置文件 beans.xml
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" 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/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- Spring IOC --> <bean id="calFab" class="day02.aop.CalFabImpl"></bean> <bean id="selfAspectRef" class="day02.aop.SelfAspect"></bean> <!-- Spring Aop 配置切麵 --> <aop:config> <!-- 配置切麵 --> <aop:aspect ref="selfAspectRef"> <!-- 切點 在CalFabImpl類的任何方法上加通知 --> <aop:pointcut expression="execution(* day02.aop.CalFabImpl.*(..))" id="selfPointcut"/> <!-- 通知 --> <aop:before method="testBefore" pointcut-ref="selfPointcut"/> <aop:after method="testAfter" pointcut-ref="selfPointcut"/> <aop:around method="testAround" pointcut-ref="selfPointcut"/> </aop:aspect> </aop:config> </beans>
新建介面 ICalFab.java
1 /** 2 * 業務介面 3 * @author 張澤 4 */ 5 public interface ICalFab { 6 7 int calFaByLoop(int n); 8 int calFabByRecursion(int n); 9 10 }
新建類實現介面:
/** * 業務實現類:被代理類 * @author 張澤 */ class CalFabImpl implements ICalFab{ @Override public int calFaByLoop(int n) { int n1=1,n2= 1,n3=0; for (int i = 3; i < n; i++) { n3=n1+n2; n1=n2; n2=n3; } return n3; } @Override public int calFabByRecursion(int n) { if(n==1||n==2) return 1; return calFabByRecursion(n-1)+calFabByRecursion(n-2); } }
新建類:SelfAspect.java
import org.aspectj.lang.ProceedingJoinPoint; /** * 自定義功能性切麵:利用xml配置實現。 * @author 張澤 * */ public class SelfAspect { //--通知:Before類型的Advice public void testBefore() { System.out.println("before do something..."); } //--通知:after類型的通知 public void testAfter() { System.out.println("after do Something..."); } //-- 通知:Around環繞 通知方法的執行點 public int testAround(ProceedingJoinPoint jp) { int result = 0; try { long start = System.currentTimeMillis(); result = (int)jp.proceed(); //-- 執行業務方法 long end = System.currentTimeMillis(); System.out.println(end-start+"ms"); } catch (Throwable e) { e.printStackTrace(); } return result; } }
新建調用類:Invoker.java
import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * Invoker類 * 功能切入更加靈活 * @author 張澤 * */ public class Invoker { public static void main(String[] args) { //-- 1. Spring容器 ApplicationContext ctx = new ClassPathXmlApplicationContext("application.xml"); //-- 2. 獲取業務類 ICalFab calFab= (ICalFab)ctx.getBean("calFab"); //-- 3. 調用業務方法 System.out.println(calFab.calFaByLoop(40)); System.out.println(calFab.calFabByRecursion(40)); System.out.println(calFab instanceof ICalFab); } }
使用 註解 配置實現具體的操作:
(1) Config類來代替xml的配置
@EnableAspectJAutoProxy //-- 啟用SpringAop的功能
//-- 啟用Spring的IOC功能
@Configuration
@ComponentScan({"package1","package2"})
(2)編寫切麵。
代碼示例:
新建介面 ICalFab.java
/** * 業務介面 * @author 張澤 * */ public interface ICalFab { int calFaByLoop(int n); int calFabByRecursion(int n); }
新建實現類 CalFabImpl.java
import org.springframework.stereotype.Component; /** * 業務實現類:被代理類 * @author 張澤 */ @Component //-- Spring IOC class CalFabImpl implements ICalFab{ @Override public int calFaByLoop(int n) { int n1=1,n2= 1,n3=0; for (int i = 3; i < n; i++) { n3=n1+n2; n1=n2; n2=n3; } return n3; } @Override public int calFabByRecursion(int n) { if(n==1||n==2) return 1; return calFabByRecursion(n-1)+calFabByRecursion(n-2); } }
新建配置類 AppConfig.java
import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; /** * 配置類 * @author 張澤 * 實現IOC功能 * */ @Configuration @EnableAspectJAutoProxy //-- 啟用SpringAop的功能 @ComponentScan("day.annocation")//-- 包名 public class AppConfig { // @Bean // public ICalFab calFabBean() { // return new CalFabImpl(); // } }
新建類:SelfAspect.java
import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; /** * 利用標註自定義切麵 * @author 張澤 * */ @Aspect @Component public class SelfAspect { //-- 1. 自定義切點,指定目標方法的位置 @Pointcut("execution(* day02.annocation.CalFabImpl.*(..))") public void selfPointcut() { } //-- 2. 通知 @Before("selfPointcut()") public void testBefore() { System.out.println("before do something..."); } @After("selfPointcut()") public void testAfter() { System.out.println("After do something..."); } @Around("selfPointcut()") public int testAround(ProceedingJoinPoint jp) { int result = 0; try { long start = System.currentTimeMillis(); result = (int)jp.proceed(); //-- 執行業務方法 long end = System.currentTimeMillis(); System.out.println(end-start+"ms"); } catch (Throwable e) { e.printStackTrace(); } return result; } }
新建類:Invoker.java
import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class Invoker { public static void main(String[] args) { //-- 1.構造Spring容器 ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class); //-- 2.獲取Beans ICalFab calFab =(ICalFab)ctx.getBean("calFabImpl");//-- 預設是類名首字母小寫 calFab.calFabByRecursion(40); //-- Web伺服器啟動的時候實例化一個Spring容器,在Web伺服器關閉的時候關閉Spring容器 //-- Servlet的監聽 //-- 容器關閉 ((AnnotationConfigApplicationContext)ctx).close(); } }
3.Spring Test
Spring 的測試框架建立在JUnit測試框架基礎上的,它是對JUnit的再次封裝。
使用:
配置文件 pom.xml 引入插件
<!-- https://mvnrepository.com/artifact/junit/junit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12-beta-3</version> <scope>test</scope> </dependency> <!-- Spring Test --> <!-- https://mvnrepository.com/artifact/org.springframework/spring-test --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.1.7.RELEASE</version> <scope>test</scope> </dependency>
示例測試工程的代碼:
/** * 業務介面 * @author 張澤 * */ public interface IUserService { void login(); }
import org.springframework.stereotype.Component; /** * 業務實現類 * @author 張澤 * */ @Component public class UserServiceImpl implements IUserService { @Override public void login() { System.out.println("login success"); } }
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; /** * Spring配置 * @author 張澤 * */ @Configuration @ComponentScan("day03") public class AppConfig { @Bean("hello") public String hello() { return "hello"; } }
import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; /** * 調用 * @author 張澤 * */ public class Invoker { public static void main(String[] args) { //-- Spring COntainer ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class); //-- 2. System.out.println(ctx.getBean("hello")); } }
JUnit測試代碼:
/** * 1. 先利用JUnit做單元測試 * @author 張澤 * */ import org.junit.Before; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class TestDemo { private ApplicationContext ctx; @Before public void before() { ctx = new AnnotationConfigApplicationContext(AppConfig.class); } @Test public void test() { System.out.println(ctx.getBean("hello")); } }
利用Spring test 框架測試:
import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; /** * 2. 利用Spring test 框架 * * @RunWith: 實例化Spring容器 * @ContextConfiguration: 指定Spring容器需要的配置類 * 以後你會很少看到Spring容器了 * */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes= {AppConfig.class}) public class TestSpringDemo { @Autowired private String hi; @Autowired private IUserService userService; @Test public void test() { System.out.println(hi); } @Test public void test1() { userService.login(); } }
該項目的配置文件:pom.xml
<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.uek.course</groupId> <artifactId>spring-app</artifactId> <version>0.0.1</version> <packaging>war</packaging> <!-- 2. 項目屬性配置 --> <properties> <!-- 項目編碼使用UTF-8 --> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <!-- 忽略掉web.xml文件 ,因為我們使用servlet3.0開發web項目 --> <failOnMissingWebXml>false</failOnMissingWebXml> <spring.version>5.1.7.RELEASE</spring.version> </properties> <!-- 3. 配置項目所需要的第三方jar 包 --> <dependencies> <!-- servlet api --> <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <!-- MySQL資料庫連接池 --> <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.48</version> </dependency> <!-- Druid --> <!-- https://mvnrepository.com/artifact/com.alibaba/druid --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.20</version> </dependency> <!-- 單元測試 --> <!-- https://mvnrepository.com/artifact/junit/junit --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12-beta-3</version> <scope>test</scope> </dependency> <!-- Spring Test --> <!-- https://mvnrepository.com/artifact/org.springframework/spring-test --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring.version}</version> <scope>test</scope> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-context --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-core --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjrt --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.8.10</version> </dependency> <!-- https://mvnrepository.com/artifact/aopalliance/aopalliance --> <dependency> <groupId>aopalliance</groupId> <artifactId>aopalliance</artifactId> <version>1.0</