Spring简介
- Spring并不是一个包含大量新技术的框架, 而是抽象了大量javaEE应用中的常用代码, 将他们抽象成一个框架。
- 你可以把Spring看成一个用来整合其他框架的框架
- Spring本身提供了一个设计优良的MVC框架:springMVC 使用Spring 可以 直接用MVC
- 对于持久层(dao层【操作数据库层】)Spring 没有提供,但是可以无缝整合其他的 持久层框架如:MyBatis,Hibernate,JPA等,甚至可以直接使用JDBC,这也是Spring 的魅力所在,给开发者提供了大量了选择权。
- 某种角度来说它更像一种容器,具有强大的生命力,贯穿三层。
Spring的具体优势
- 轻量级:Spring框架的核心库非常精简,不需要依赖庞大的第三方库,可以快速部署和运行,占用的系统资源也较少。
- 控制反转、依赖注入(IOC、DI):Spring通过IoC技术促进了代码的松耦合。对象之间的依赖关系由框架来管理,降低了类之间的紧耦合度,提高了代码的灵活性和可测试性。
- 面向切面编程(AOP):Spring提供了AOP支持,允许开发者将横切关注点(如日志、事务管理等)从业务逻辑中分离出来,提高了代码的可重用性和可维护性。
- 方便的测试:Spring对单元测试和集成测试提供了良好的支持。通过Spring的依赖注入和AOP等特性,可以方便地编写可测试的代码。
- 模块化和可扩展性:Spring框架采用分层的设计思想,将应用程序划分为不同的模块。这种模块化的设计使得应用程序更加易于维护和扩展。
- 支持声明式事务管理:Spring提供了事务管理的支持,允许开发者通过简单的配置来管理事务,而无需编写繁琐的事务管理代码。
- 丰富的功能模块:Spring框架提供了数据访问、事务管理、Web开发、安全性等多个功能模块,这些模块都经过了良好的设计和测试,可以方便地与Spring的核心模块集成。
Spring核心
- Spring 容器管理 bean 各层对象,管理的是对象的声明周期和 对象的依赖关系(依赖注入)
- 理解什么是依赖: 依赖就是一种关系,比如controller依赖 service ,service 依赖 dao,也可以认为是A组件调用了B组件的方法,那么就认为A依赖B ,A可以多依赖
-
依赖注入:用spring容器给Bean注入对象,也可以注入普通的属。这种方式是一种优秀的解耦方式,一配置文件的形式组织在一起,而不是硬编码的方式(service层 new 一个dao的实例),
-
什么时控制反转:原本一个类需要一个对象时,要去主动获取,工厂里或者直接创建,现在只需要由Spring 给你被动的注入你需要的东西,所以控制的方式发生反转(与依赖注入完全一个东西理解角度不同罢了)
使用了Spring框架后:
程序员无须使用new调用构造器去创建对象。所有的Java对象都可以交给Spring容器去创建。
当调用者需要调用被依赖对象的方法时,调用者无须主动获取依赖对象,只要等待spring容器注入即可。
准备工作
创建一个java maven 项目
导入如下jar包
注意junit 如果你想在非测试文件里面使用test 就把下面的限制范围搞没就行了(复制代码就行)
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.20</version>
</dependency>
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
<scope>provided</scope>
</dependency>
</dependencies>
主备两个java bean
@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class People {
private String name = "a_people";
private Integer age;
private Cat cat;
}
@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class Cat {
private String name = "little_cat";
private Integer age;
}
Spring xml 文件创建对象
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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- spring 容器首先管理对对象的创建-->
<!-- 1:无参构造创建对象-->
<bean class="com.wolf.bean.Cat" id="cat"></bean>
<bean class="com.wolf.bean.People" id="people"></bean>
</beans>
查看我们创建的javabean 和他们的关系
test测试单元
通过类路径下 spring 文件名称找到 Spring 配置文件 生成容器对象
然后从容器中拿出通过无参构造创建的对象, 对象打印
getBean("spring.xml里面定义的id值", "对象的Class类")
public class Test01 {
@Test
public void test() throws Exception{
// ApplicationContext 是应用上下文 即 spring 容器对象
ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
Cat cat = ac.getBean("cat", Cat.class);
People people = ac.getBean("people", People.class);
System.out.println(cat);
System.out.println(people);
}
}
运行结果
静态工厂创建Bean
工厂准备
一个接口 Flyable 和连个 实现类 CanFly CannotFly 和一个 FlyFactory01工厂
public interface Flyable {
public void fly();
}
public class CannotFly implements Flyable {
@Override
public void fly() {
System.out.println("不可以飞");
}
}
public class CanFly implements Flyable {
@Override
public void fly() {
System.out.println("可以飞");
}
}
public class FlyFactory01 {
public static Flyable get(String choose){
if("can".equalsIgnoreCase(choose)) {
return new CanFly();
}else if("cannot".equalsIgnoreCase(choose)){
return new CannotFly();
}else {
return null;
}
}
}
xml文件
传入工厂类路径 id 为标识 工厂方法是你定义的 内部名为get 的方法 所以是get
里面的标签是指 名称为choose 值为 can / cannot 的 参数(相当与调用了factory 的方法)
<!-- 2.工厂方式 静态工厂方法-->
<bean id="canA" class="com.wolf.factory01.FlyFactory01" factory-method="get">
<constructor-arg value="can" name="choose"/>
</bean>
<bean id="cannotA" class="com.wolf.factory01.FlyFactory01" factory-method="get">
<constructor-arg name="choose" value="cannot"/>
</bean>
test类
public class TestStaticFactory {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
Flyable canA = ac.getBean("canA", Flyable.class);
Flyable cannotA = ac.getBean("cannotA", Flyable.class);
canA.fly();
cannotA.fly();
}
}
运行结果
非静态工厂创建Bean
参照上面的静态工厂的所有东西
只是里面的 factory中静态方法换成 方法不能直接类调用 需要有实例
xml
这个不同了 先创建一个工厂实例 再用 factory-bean 使用它 class 从工厂变为了 生成对象的 接口
<!--3.工厂方法-->
<bean id="flyfactory02" class="com.wolf.factory01.Flyfactory02"></bean>
<bean id="canB" class="com.wolf.factory01.Flyable" factory-bean="flyfactory02" factory-method="get">
<constructor-arg name="choose" value="can"/>
</bean>
<bean id="cannotB" class="com.wolf.factory01.Flyable" factory-bean="flyfactory02" factory-method="get">
<constructor-arg name="choose" value="cannot"/>
</bean>
调用也是一样的 用id 和 接口就可以拿出来 调用方法即可
Spring注入(重点)
set注入和构造注入
新建两个javaBean
wolf 和 wolfKing
@Data
@ToString
public class Wolf {
private String name;
private Integer age;
public Wolf() {
}
}
@Data
@ToString
public class WolfKing {
private String name;
private Integer age;
private Wolf wolf;
private String[] hobbyArray;
private List<Integer> scoreList;
private Set<String> schoolSet;
private Map<String, String> sizeMap;
private Properties prop;
public WolfKing() {
}
}
xml
property 是set
constructor-arg 是构造进去的
可以先构造再注入也行
里面的这些特殊数据也好办 都给了相应的标签了
<!-- set 和 构造注入-->
<bean id="wolf01" class="com.wolf.bean.Wolf">
<property name="name" value="little_wolf01"/>
<property name="age" value="2"/>
</bean>
<bean class="com.wolf.bean.WolfKing" id="wolfKing">
<property name="name" value="bigWolf"/>
<property name="age" value="5"/>
<!-- ref 关联上面创建的wolf-->
<property name="wolf" ref="wolf01"/>
<!-- string[] -->
<property name="hobbyArray">
<array value-type="java.lang.String">
<value>football</value>
<value>basketball</value>
<value>swimming</value>
</array>
</property>
<!-- list<Integer>-->
<property name="scoreList">
<list value-type="java.lang.Integer">
<value>100</value>
<value>20</value>
</list>
</property>
<!-- set<String>-->
<property name="schoolSet">
<set value-type="java.lang.String">
<value>嗷呜~!</value>
<value>呜呜~~</value>
</set>
</property>
<!-- map<stirng,string>-->
<property name="sizeMap">
<map key-type="java.lang.String" value-type="java.lang.String">
<entry key="aowu1" value="狠狠吃肉肉"/>
<entry key="aowu2" value="狠狠睡觉觉"/>
</map>
</property>
<property name="prop">
<props>
<prop key="IQ">666</prop>
<prop key="EQ">555</prop>
</props>
</property>
</bean>
<!-- 构造创建-->
<bean id="wolf02" class="com.wolf.bean.Wolf">
<constructor-arg name="name" value="little_wolf"/>
<constructor-arg value="1" name="age"/>
</bean>
结果
一行太长了分开
用命名空间简化注入 + 多例和单例
用命名空间简化配置 p:代表set注入 c:构造注入
scope 来调整 单例还是 多例 -> scope="prototype" 默认单例-> scope="singleton"
<?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:util="http://www.springframework.org/schema/util"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
https://www.springframework.org/schema/util/spring-util.xsd">
<!-- 用命名空间简化配置 p:代表set注入 c:构造注入 -->
<!-- scope 来调整 单例还是 多例 -> scope="prototype" 默认单例-> scope="singleton"-->
<bean class="com.wolf.bean.Wolf" id="wolf01" p:name="little_aowu01" p:age="5" />
<bean class="com.wolf.bean.Wolf" id="wolf02" c:name="little_aowu02" c:age="4" scope="prototype"/>
</beans>
外部设置一些集合util
<!-- 外部设置一些集合-->
<util:map key-type="java.lang.String" value-type="java.lang.String">
<entry key="key1" value="value1"/>
<entry key="key2" value="value2"/>
<entry key="key3" value="value3"/>
</util:map>
自动注入autowire
1.bytype 现在 狼王想匹配一只小狼 用自动配置通过类型匹配, 要求这个bean必须是唯一类型这里指的是wolf的bean只能有一个 第二个出现时 狼王的bean会报错 所以我注掉了
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="com.wolf.bean.Wolf" id="wolf01">
<property name="name" value="little_wolf01"/>
<property name="age" value="3"/>
</bean>
<!-- <bean class="com.wolf.bean.Wolf" id="wolf02">-->
<!-- <property name="name" value="little_wolf02"/>-->
<!-- <property name="age" value="4"/>-->
<!-- </bean>-->
<bean class="com.wolf.bean.WolfKing" id="wolfKing01" autowire="byType">
<property name="name" value="wolfKing01"/>
</bean>
</beans>
2.byname 是允许多个 wolf 存在 但是必须有一个的 id 是wolf 顾名思义 byname通过类名来自动匹配
3.默认是 no
操作数据库(重点)
druid连接池
先导包
<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.8</version>
</dependency>
druid 连接池的配置文件如下
mysql.driverClassName=com.mysql.cj.jdbc.Driver
mysql.url=jdbc:mysql://localhost:3306/mvnproject?useSSL=false&serverTimezone=Asia/Shanghai
mysql.username=root
mysql.password=123456
mysql.filters=stat
mysql.initialSize=2
mysql.maxActive=300
mysql.maxWait=60000
mysql.timeBetweenEvictionRunsMillis=60000
mysql.minEvictableIdleTimeMillis=300000
mysql.validationQuery=SELECT 1
mysql.testWhileIdle=true
mysql.testOnBorrow=false
mysql.testOnReturn=false
mysql.poolPreparedStatements=false
mysql.maxPoolPreparedStatementPerConnectionSize=200
xml文件如下
先扫描druid.properties 配置文件 (property- placeholder 属性占位)
才能在下面的配置中应用占位符
init 和destroy 是 容器创建时 进行的方法 destroy 是销毁时执行的方法 这两个方法在 连接池jar包中以及写好了, 是方法
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 加载druid.propertis 配置文件-->
<context:property-placeholder location="classpath:druid.properties"/>
<!-- set注入创建 dataSource 对象-->
<bean class="com.alibaba.druid.pool.DruidDataSource" id="dataSource
init-method="init" destroy-method="close">
<property name="driverClassName" value="${mysql.driverClassName}"/>
<property name="url" value="${mysql.url}"/>
<property name="username" value="${mysql.username}"/>
<property name="password" value="${mysql.password}"/>
<property name="initialSize" value="${mysql.initialSize}"/>
<property name="maxActive" value="${mysql.maxActive}"/>
<property name="maxWait" value="${mysql.maxWait}"/>
</bean>
</beans>
同样的里面也有工厂来创建 dataSource 对象 显然这个是静态工厂
管理JDBCTemplate
先导包
spring管理jdbc
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.20</version>
</dependency>
智能的maven 重复的会包会 omitted 忽略掉
xml
在之前的druid基础上 多加个配置 jdbc 即可
<!-- 配置jdbc-->
<bean class="org.springframework.jdbc.core.JdbcTemplate" id="jdbcTemplate">
<property name="dataSource" ref="dataSource"/>
</bean>
续: 一般用springboot 后面 springboot + mybatis-plus + git + maven 组成项目 的核心后端框架 这个作为了解就可以了