Spring框架 --- 深入
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</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> </dependencies> <!-- 配置构建插件 --> <build> <plugins> <plugin> <!-- 编译插件 --> <artifactId>maven-compiler-plugin</artifactId> <version>3.5.1</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> <!-- Tomcat 插件 --> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.2</version> <configuration> <port>8080</port> <path>/airsys</path> <!-- 实现热部署,不需要每次修改代码后都重新启动Tomcat --> <contextReloadable>true</contextReloadable> </configuration> </plugin> </plugins> </build> </project>