From 05a6f4f6f810df65a836740bc6283f0a0f8e3b8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8F=AB=E6=88=91=E6=99=93=E6=99=93?= Date: Mon, 12 Oct 2020 14:07:47 +0800 Subject: [PATCH] =?UTF-8?q?Update=20Spring=E5=BF=AB=E9=80=9F=E4=B8=8A?= =?UTF-8?q?=E6=89=8B.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...53\351\200\237\344\270\212\346\211\213.md" | 426 +++++++++++++++++- 1 file changed, 419 insertions(+), 7 deletions(-) diff --git "a/Spring\345\277\253\351\200\237\344\270\212\346\211\213.md" "b/Spring\345\277\253\351\200\237\344\270\212\346\211\213.md" index b8e4284..8be6f07 100644 --- "a/Spring\345\277\253\351\200\237\344\270\212\346\211\213.md" +++ "b/Spring\345\277\253\351\200\237\344\270\212\346\211\213.md" @@ -6,8 +6,6 @@ Spring是分层的JavaSE/EE应用full-stack(全栈的)轻量级开源框架,它有两个核心思想:**IoC**(Inverse of Control,控制反转)和 **AOP**(Aspect Oriented Programming,面向切面编程),提供了展现层 SpringMVC 和持久层 Spring JDBC 以及业务层事务管理等众多的企业级应用技术,还能整合开源世界众多著名的第三方框架和类库,现在逐渐成为最受欢迎的JavaEE企业开源开发框架。 -![核心架构](../../../图片/博客/Spring_Structure.jpg) - ## 为什么使用Spring框架——Spring框架的优点 1. **便于程序间解耦,使得开发更简洁** @@ -486,6 +484,56 @@ http://www.springframework.org/schema/beans/spring-beans.xsd"> |1|Zero|1559503| |2|Sharon|155345| +#### Maven坐标pom.xml + +```xml + + 4.0.0 + + top.aerlee + shogirlsAnnowithoutxml + 0.0.1-SNAPSHOT + jar + + shogirlsAnnowithoutxml + http://maven.apache.org + + + UTF-8 + + + + + junit + junit + 4.12 + test + + + org.springframework + spring-context + 5.2.9.RELEASE + + + mysql + mysql-connector-java + 5.1.6 + + + commons-dbutils + commons-dbutils + 1.4 + + + c3p0 + c3p0 + 0.9.1.2 + + + +``` + #### 实体类,业务层及Dao层类 ```java @@ -609,7 +657,7 @@ public class GirlDaoImpl implements GirlDao{ #### 配置Spring Ioc(编写xml配置文件) -我们打算使用ClassPathXmlApplicationContext,所以我们打xml文件放在main.java包下,命名为beans.xml +我们打算使用ClassPathXmlApplicationContext,所以我们将xml文件放在main.java包下,命名为beans.xml ```xml @@ -619,12 +667,12 @@ public class GirlDaoImpl implements GirlDao{ https://www.springframework.org/schema/beans/spring-beans.xsd"> - + - + @@ -860,9 +908,73 @@ public static void main(String[] args) { } ``` -### 摆脱xml配置文件实现纯注解配置 +### 摆脱xml配置文件实现纯注解配置Spring IoC + +通过定义一个类,在该类上面添加相应的注解来配置之前在xml中的配置。还是基于前面我们的数据库查询案例,不过这里将使用配置类来替代xml配置文件。接口没有变化,只是在接口的实现类中,我们改用注解实现对象创建及依赖注入。 + +```java +package top.aerlee.dao.impl; + +import java.util.List; +import org.apache.commons.dbutils.QueryRunner; +import org.apache.commons.dbutils.handlers.BeanListHandler; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Repository; +import top.aerlee.dao.GirlDao; +import top.aerlee.domain.Girl; + +/** + * Dao层实现类 + * @author vincent + * + */ +@Repository("daoAnno") +public class GirlDaoAnnoImpl implements GirlDao{ + @Autowired + private QueryRunner runner; + + public void setRunner(QueryRunner runner) { + this.runner = runner; + } + + public List showAll() { + List list = null; + try { + list = runner.query("select * from girls", new BeanListHandler(Girl.class)); + } catch (Exception e) { + e.printStackTrace(); + } + return list; + } +} +``` -通过定义一个类,在该类上面添加相应的注解来配置之前在xml中的配置。 +```java +package top.aerlee.service.impl; + +import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import top.aerlee.dao.GirlDao; +import top.aerlee.domain.Girl; +import top.aerlee.service.GirlService; +/** + * 业务层实现类 + * @author vincent + * + */ +@Service("serviceAnno") +public class GirlServiceAnnoImpl implements GirlService{ + @Autowired + private GirlDao dao; + public void setDao(GirlDao dao) { + this.dao = dao; + } + public List showAll() { + return dao.showAll(); + } +} +``` #### @Configuration @@ -907,3 +1019,303 @@ public class Springconfig { } ``` +#### @Bean + +该注解只能写在方法上,表明使用此方法创建一个对象,并且放入 Spring 容器。 + +属性:name,给当前@Bean 注解方法创建的对象指定一个名称,即 bean 的 id。 + +```java +package top.aerlee.configurations; + +import javax.sql.DataSource; +import org.apache.commons.dbutils.QueryRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import com.mchange.v2.c3p0.ComboPooledDataSource; + +/** + * 配置类 + * @author vincent + */ +@Configuration +@ComponentScan("top.aerlee") +public class SpringConfig { + + @Bean(name = "runner") + public QueryRunner createRunner(DataSource datasource) { + return new QueryRunner(datasource); + } + + @Bean(name = "datasource") + public DataSource createDataSource() { + ComboPooledDataSource cds = new ComboPooledDataSource(); + try { + cds.setDriverClass("com.mysql.jdbc.Driver"); + cds.setJdbcUrl("jdbc:mysql://localhost:3306/girlsinfo"); + cds.setUser("数据库用户名"); + cds.setPassword("密码"); + return cds; + } catch (Exception e) { + // TODO: handle exception + e.printStackTrace(); + } + return cds; + } +} +``` + +在这里使用了@Bean注解,在配置类中将DataSource对象创建并且加入到了Spring容器中,但是这样还是有一个问题,那就是关于数据库连接相关的配置都被写死在了配置类中,如果遇到了更换数据库连接等情况的话,还要更改源代码,是比较麻烦的。使用@@PropertySource注解可以解决这个问题。 + +#### @PropertySource + +用于加载 .properties文件中的配置 。 例如:我们配置数据源时 , 可以把连接数据库的信properties配置文件中,就可以使用此注解指定properties配置文件的位置。 +属性:value[]:用于指定properties文件位置。如果是在类路径下,需要写上"classpath:",在前面我们讲过,如果使用@Value注解来注入数据的时候,是支持"SPEL表达式"的。 + +我们可以将数据库连接信息写成一个JdbcLink.properties配置文件放在类路径下,在配置文件中使用@PropertySource注解来配置。 + +```reStructuredText +driver=com.mysql.jdbc.Driver +url=jdbc:mysql://localhost:3306/girlsinfo +username=vincent +password=vincent12345 +``` + +```java +package top.aerlee.configurations; + +import javax.sql.DataSource; +import org.apache.commons.dbutils.QueryRunner; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; +import com.mchange.v2.c3p0.ComboPooledDataSource; + +/** + * 配置类 + * 在这里我们使用了@PropertySource注解将之前配置在JdbcLink.properties配置文件中的连接数据引入 + * 从而解决了前面提到的配置信息写死的问题。 + * @author vincent + * + */ +@Configuration +@ComponentScan("top.aerlee") +@PropertySource("classpath:JdbcLink.properties") +public class SpringConfig2 { + // 定义数据库连接相关信息对应的变量 + @Value("${driver}") + private String driver; + @Value("${url}") + private String url; + @Value("${username}") + private String username; + @Value("${password}") + private String password; + + @Bean(name = "runner") + public QueryRunner createRunner(DataSource datasource) { + return new QueryRunner(datasource); + } + + @Bean(name = "datasource") + public DataSource createDataSource() { + ComboPooledDataSource cds = new ComboPooledDataSource(); + try { + cds.setDriverClass(driver); + cds.setJdbcUrl(url); + cds.setUser(username); + cds.setPassword(password); + return cds; + } catch (Exception e) { + e.printStackTrace(); + } + return cds; + } +} +``` + +#### @Import + +用于导入其他配置类 +属性:value[]:用于指定其他配置类的字节码。 + +在实际的开发中,我们需要配置的内容显然不止JDBC,为了便于维护,我们可以将配置写在多个配置类中,成为子配置类,而SpringConfig类就是主配置类,当我们将子配置类写好之后,在主配置类中使用@Import注解可以将子配置类引入。 + +```java +package top.aerlee.configurations; + +import javax.sql.DataSource; +import org.apache.commons.dbutils.QueryRunner; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; +import com.mchange.v2.c3p0.ComboPooledDataSource; + +/** + * 子配置类,在主配置类中通过@Import注解来导入 + * @author vincent + */ +@Configuration +@PropertySource("classpath:JdbcLink.properties") +public class JdbcConfig { + + @Value("${driver}") + private String driver; + @Value("${url}") + private String url; + @Value("${username}") + private String username; + @Value("${password}") + private String password; + + @Bean(name = "runner") + public QueryRunner createRunner(DataSource datasource) { + return new QueryRunner(datasource); + } + + @Bean(name = "datasource") + public DataSource createDataSource() { + ComboPooledDataSource cds = new ComboPooledDataSource(); + try { + cds.setDriverClass(driver); + cds.setJdbcUrl(url); + cds.setUser(username); + cds.setPassword(password); + return cds; + } catch (Exception e) { + e.printStackTrace(); + } + return cds; + } +} +``` + +```java +package top.aerlee.configurations; + +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; + +/** + * 主配置类 + * 在这里,我们使用了@Import注解将JdbcConfig配置类导入了主配置类中 + * @author vincent + */ +@Configuration +@ComponentScan("top.aerlee") +@Import(JdbcConfig.class) +public class SpringConfig { + +} +``` + +#### 创建纯注解环境的容器 + +在使用xml或者使用半注解配置Spring IoC时,我们使用了`ClassPathXmlApplicationContext`类来创建Spring IoC容器,而现在我们使用纯注解的方式来配置,将使用`AnnotationConfigApplicationContext`类来创建容器,它的参数不再是配置文件,而是配置类的class。 + +```java +package top.aerlee.test; + +import java.util.List; +import org.junit.Test; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import top.aerlee.configurations.SpringConfig; +import top.aerlee.domain.Girl; +import top.aerlee.service.GirlService; +import top.aerlee.service.impl.GirlServiceAnnoImpl; + +public class TestIoCAnno { + + @Test + public void TestShowAll() { + AnnotationConfigApplicationContext aContext = new AnnotationConfigApplicationContext(SpringConfig.class); + GirlService service = (GirlService)aContext.getBean("serviceAnno",GirlServiceAnnoImpl.class); + List list = service.showAll(); + for(Girl girl : list) { + System.out.println(girl); + } + aContext.close(); + } +} +``` + +## Spring 整合Junit测试功能 + +在上面的测试案例中,因为在程序运行之前我们需要创建容器,我们将创建容器的代码写在了Test方法中,这意味着,每个@Test方法中我们都要写这部分代码。在以前,我们使用@Before注解来将这部分代码提取出去;但是在实际开发中,测试工程师和软件开发工程师是两个岗位,我们想要的是直接让它自动创建容器,这就需要整合Spring和Junit。Junit无法实现自动创建Spring容器的功能,但是Junit提供了一个注解@Runwith,它支持将Junit的运行器改为Spring提供的运行器,它可以自动创建容器。 + +### 配置整合环境 + +导入坐标,我们需要一个spring-test的jar包,和Junit4.12以上的包,同时spring-aop的jar包也是必须的。 + +```xml + + org.springframework + spring-test + 5.2.9.RELEASE + +``` + +### 使用@RunWith 注解替换原有运行器 + +````java +@RunWith(SpringJUnit4ClassRunner.class) +public class TestIoCAnno { +} +```` + +### 使用@ContextConfiguration注解指定 spring 配置文件的位置 + +如果使用的是xml文件配置的,那么就使用locations属性指定配置文件打位置,如果使用的是注解配置的,那就使用classes属性指定配置类的classes文件。 + +```java +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes=SpringConfig.class) +public class TestIoCAnno { +} +``` + +```java +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(locations="classpath:bean.xml") +public class TestIoCAnno { +} +``` + +### 使用@Autowired 给测试类中的变量注入数据 + +```java +package top.aerlee.test; + +import java.util.List; +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; +import top.aerlee.configurations.SpringConfig; +import top.aerlee.domain.Girl; +import top.aerlee.service.GirlService; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration(classes=SpringConfig.class) +public class TestIoCAnno { + + @Autowired + GirlService service; + + @Test + public void TestShowAll() { + List list = service.showAll(); + for(Girl girl : list) { + System.out.println(girl); + } + } +} +``` + +在这里,不再需要容器对象了,因为使用Spring整合Junit的方式的话,容器会自动创建,容器创建后,GirlService对象也会被创建,在这里直接使用@Autowired注解注入即可。 \ No newline at end of file -- GitLab