Spring 是一个分层的一站式轻量级开源框架,提供了多个模块给用户自由组合,能有效解决复杂的企业级应用
(1)spring属于低侵入式设计,代码的污染极低;
(2)spring的DI机制将对象之间的依赖关系交由框架处理,减低组件的耦合性;
(3)Spring提供了AOP技术,支持将一些通用任务,如安全、事务、日志、权限等进行集中式管理,从而提供更好的复用。
(4)spring对于主流的应用框架提供了集成支持。
通俗地说,所谓的控制反转就是用工厂模式将模块包装起来,其他模块要使用时由工厂统一管理和处理。IOC 则是由一个个这样的工程组合而成的。
假设有 A、B 两个模块,若 A 模块需要使用到 B 模块的对象
没有IOC容器的时候:
没有 IOC 容器时,A模块需要在初始化或某个节点时 new 一个 B 对象或使用已有的 B 对象,而这个主动权在 A 模块中,A 模块能选择使用哪种 B 模块对象,是 new 一个新的,还是使用已有的
使用IOC容器后:
使用 IOC 容器后,所有的 B 对象都由 IOC 容器统一管理,在项目运行后,IOC容器发现A需要使用B,就从B工厂中生成一个B并发送给A
控制 -- 反转
控制:结合例子,可以发现对象的创建交给了 IOC 容器实现,即对象的创建和控制权交给了 IOC 容器,这就是Spring中的控制
反转:结合例子,未使用 IOC 容器时,对象的创建权和控制权是在他的调用对象手中的。
使用了 IOC 容器后,对象的创建权和控制权都交给了 IOC 容器,而调用他的对象模块只能使用 IOC 容器返回的对象。这
也就是依赖注入
DI—Dependency Injection,即“依赖注入”:是组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。
依赖 -- 注入
依赖:组件依赖于 IOC 容器,通过 IOC 容器来提供对象所需要的资源,实现组件间的解耦
注入:调用组件的模块,通过向 IOC 容器获取,得到所需对象的过程,叫做注入
Spring 框架是一个分层架构,由 7 个定义良好的模块组成。Spring 模块构建在核心容器之上,核心容器定义了创建、配置和管理 bean 的方式
组成 Spring 框架的每个模块(或组件)都可以单独存在,或者与其他一个或多个模块联合实现。每个模块的功能如下:
BeanFactory
,它是工厂模式的实现。 BeanFactory
使用 控制反转 (IOC) 模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。
三种实现类:
配置方式:
public static void main(String[] args) {
// 1. 获取核心容器对象
// ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
ApplicationContext ac = new FileSystemXmlApplicationContext("E:\\study\\project\\spring\\spring-demo03\\src\\main\\resources\\bean.xml");
// 2. 根据ID获取Bean对象
IAccountService accountService = ac.getBean("accountService", IAccountService.class);
accountService.saveAccount();
AccountDao accountDao = ac.getBean("accountDao", AccountDao.class);
accountDao.saveAccount();
}
ApplicationContext | BeanFactory | |
区别 | 在构建核心容器时,创建对象采取的策略是立即加载的方式,即已读取完配置文件马上就会创建文件中配置的对象 | 在构建核心容器时,采用的是延迟加载的方式。即什么时候根据 id 获取对象了,什么时候才真正创建对象 |
使用难度 | 简单 | 复杂 |
功能 | 由 BeanFactory 派生,且支持更多扩展功能 | 古老的接口,功能较少 |
推荐使用 | 单例模式下,更推荐使用 | 非单例模式,可以使用 |
推荐原因:
依赖:
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
</dependencies>
ApplicationContext
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
// 2. 根据ID获取Bean对象
IAccountService accountService = ac.getBean("accountService", IAccountService.class);
accountService.saveAccount();
}
BeanFactory
public static void main(String[] args) {
Resource resource = new ClassPathResource("bean.xml");
BeanFactory factory = new XmlBeanFactory(resource);
IAccountService accountService = factory.getBean("accountService", IAccountService.class);
accountService.saveAccount();
}
使用默认构造函数创建,若类中没有默认构造函数,则对象无法创建
<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 id="accountService" class="com.tom.www.service.impl.AccountServiceImpl"></bean>
</beans>
这种是使用某个类中的方法,并存入 spring 容器
/**
* 模拟一个工厂类(该类可能是存在于 jar 包中的,我们无法通过修改源码的方式来提供默认构造函数)
*/
public class InstanceFactory{
public IAccountService getAccountService() {
return new IAccountServiceImpl();
}
}
<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容器) -->
<bean id="instanceFactory" class="com.tom.www.factory.InstanceFactory"></bean>
<bean id="accountService" factory-bean="instanceFactory" factory-method="getAccountService"></bean>
</beans>
/**
* 模拟一个工厂类(该类可能是存在于 jar 包中的,我们无法通过修改源码的方式来提供默认构造函数)
*/
public class StaticFactory{
public static IAccountService getAccountService() {
return new IAccountServiceImpl();
}
}
<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容器) -->
<bean id="accountService" class="com.tom.www.factory.StaticFactory" factory-method="getAccountService"></bean>
</beans>
属性 | 描述 |
singleton (默认) | 单例模式使用 |
prototype | 多例模式 |
request | 为每一个网络请求创建一个实例,在请求完成以后,bean会失效并被垃圾回收器回收 |
session | 与request范围类似,确保每个session中有一个bean的实例,在session过期后,bean会随之失效 |
global-session | 全局作用域,global-session和Portlet应用相关。当你的应用部署在Portlet容器中工作时,它包含很多portlet。如果你想要声明让所有的portlet共用全局的存储变量的话,那么这全局变量需要存储在global-session中。全局作用域与Servlet中的session作用域效果相同 |
使用 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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="accountDao" class="com.tom.dao.AccountDao" scope="singleton"></bean>
</beans>
出生 | 活着 | 死亡 | 总结 | |
单例对象 | 当容器创建时对象出生 | 只要容器还在,对象一直活着 | 容器销毁,对象消亡 | 单例对象的生命周期与容器相同 |
多例对象 | 当我们使用对象时由spring框架创建 | 对象只要在使用,就一直活着 | 当对象长时间不用,且没有别的对象引用时,由java的垃圾回收器回收 |
在IOC的作用中,当一个类需要使用到其他类的对象,由IOC容器为我们提供,我们只需要在配置文件中说明,这样使用类通过被使用类获取对象的方式,我们就称为依赖注入。
<!-- 构造函数注入
使用标签:constructor-arg
标签出现的为止: bean标签内部
标签中的属性:
type: 用于指定要注入的数据的数据类型,该数据类型也是构造函数中某个或某些参数的类型
index: 用于指定要注入的数据给构造函数中指定索引位置的参数赋值,索引位置从0开始
name(c常用): 用于指定给构造函数中指定名称的参数赋值
======================= 以上三个用于指定给构造函数中哪个参数赋值 =====================
value: 用于提供基本类型和string类型的数据
ref: 用于指定其他的bean类型数据,即在spring的ioc容器中出现过的bean对象
优势:
在获取bean对象时,注入数据是必须的操作,否则对象无法创建成功
弊端:
改变了 Bean 对象的实例化方式,使我们在创建对象时,若用不到这些数据,也必须提供
-->
<bean id="accountService" class="xyz.tom.www.service.impl.AccountServiceImpl">
<constructor-arg name="name" value="小明"></constructor-arg>
<constructor-arg name="age" value="18"></constructor-arg>
<constructor-arg name="birthday" ref="now"></constructor-arg>
</bean>
<!-- 配置一个日期对象 -->
<bean id="now" class="java.util.Date"></bean>
<!-- set方法注入
设计的标签: property
出现的为止: bean标签的内部
标签中的属性:
name(c常用): 用于指定注入时所调用的set方法名称
value: 用于提供基本类型和string类型的数据
ref: 用于指定其他的bean类型数据,即在spring的ioc容器中出现过的bean对象
优势:
创建对象时没有明确的限制,可以使用默认构造函数
弊端:
如果有某个成员必须有值,则获取对象时有可能set方法没有执行
-->
<bean id="accountService2" class="xyz.tom.www.service.impl.AccountServiceImpl2">
<property name="name" value="test"></property>
<property name="birthday" ref="now"></property>
</bean>
<!-- 复杂类型的注入/集合类型的注入
用于给List结构集合注入的标签: list array set
用于给Map结构注入的标签: map props
同类型可以互换,即只要记: list map
-->
<bean id="accountService3" class="xyz.tom.www.service.impl.AccountServiceImpl3">
<property name="myStrs">
<array>
<value>AAA</value>
<value>BBB</value>
<value>CCC</value>
</array>
</property>
<property name="myList">
<list>
<value>AAA</value>
<value>BBB</value>
<value>CCC</value>
</list>
</property>
<property name="mySet">
<set>
<value>AAA</value>
<value>BBB</value>
<value>CCC</value>
</set>
</property>
<property name="myMap">
<map>
<entry key="testA" value="aaa"></entry>
<entry key="testB">
<value>BBB</value>
</entry>
</map>
</property>
<property name="myProps">
<props>
<prop key="testA">AAA</prop>
<prop key="testB">BBB</prop>
<prop key="testC">CCC</prop>
</props>
</property>
</bean>
使用注解前,需要在 bean.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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="xyz.tom"></context:component-scan>
</beans>
常用的注解:
属性名 | 作用 | 位置 | 限制 |
@Component | 创建 Bean 对象 | 类名头部 | |
@Autowired | 注入变量 | 变量上,或方法上 | 要求 bean 的 id 唯一 |
@Value | 注入基本类型或string类型数据 | 变量上 | ${“xxx.xxx”} |
@Scope | 改变 Bean 对象的作用范围 | 类名头部 | |
@PreDestory、@PostConstruct | 生命周期,指定销毁方法和初始方法 | 方法上 | |
@Qualifier | 存在多个对象类型时,可以指定使用哪一个对象类型 | 类名头部 |
根据mvc三层框架,spring分别提供了三个注解,这三个注解其实是一样的,只是使用地方有所区别:
新建 SpringConfiguration.java 类,作为 Spring 项目配置的根本配置类
@Configuration
@ComponentScan({"com.tom"})
public class SpringConfiguration {
}
修改启动类
public static void main(String[] args) {
ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfiguration.class);
IAccountService accountService = ac.getBean("accountService", IAccountService.class);
accountService.saveAccount();
}
在实际开发中,Spring 允许使用 @Import 注解加载其他配置
新建数据库配置类 JdbcConfig.java
// 表明这是一个配置类,会被扫描器扫到
public class JdbcConfig {
....
}
在主配置类中引用
@ComponentScan({"xyz.tom"}) // 指定父类路径
@Import(JdbcConfig.class) // 导入子类,此时子类无需加 @Configuration
public class SpringConfiguration {
...
}
在 resources 文件夹下创建 jdbcConfig.properties:
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://www.xxxx.xyz:3306/mysql?useUnicode=true&characterEncoding=utf8&useSSL=false
jdbc.user=root
jdbc.password=root
在配置类中,使用 @PropertySource 引入
//@Configuration
@ComponentScan({"xyz.tom"})
@Import(JdbcConfig.class)
@PropertySource("classpath:jdbcConfig.properties")
public class SpringConfiguration {
}
在配置类中,用 @Value 使用
public class JdbcConfig {
@Value("${jdbc.driver}")
private String dirver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
/*
* 用于创建一个 QueryRunner 对象
*/
@Bean(name = "runner")
// @Scope(value = "prototype")
public QueryRunner createQueryRunner(DataSource datasource) {
return new QueryRunner(datasource);
}
/*
* 用于创建一个数据源对象
*/
@Bean(name="dataSource")
public DataSource createDataSource() {
ComboPooledDataSource ds = new ComboPooledDataSource();
try {
ds.setDriverClass(dirver);
// System.out.println(url);
// ds.setDriverClass("com.mysql.cj.jdbc.Driver");
ds.setJdbcUrl(url);
ds.setUser(username);
ds.setPassword(password);
return ds;
} catch (PropertyVetoException e) {
throw new RuntimeException(e);
}
}
}
加入依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
创建测试类
/*
* 使用Junit单元测试,测试我们的配置
* Spring整合junit的配置
* 1. 导入spring整合junit的jar
* 2. 使用Junit提供的一个注解将原有的main方法替换,改成spring提供的
* @RunWith
* 3. 告知spring的运行期,spring和ioc创建是基于xml还是注解的,并说明位置
* @ContextConfiguration
* locations: 指定xml文件的位置,加上classpath关键字,表示在类路径下
* classes: 指定注解类所在位置
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfiguration.class)
public class MainTest{
@Autowired
private IAccountService as;
@Test
public void test() {
as.saveAccount();
}
}
动态代理的作用是在不改变原有相关代码的情况下,实现对方法的增强。如统一的拦截
8.1 AOP 的概念
本文地址:https://blog.csdn.net/qq_34416331/article/details/107365760
如对本文有疑问, 点击进行留言回复!!
浅谈Java如何实现一个基于LRU时间复杂度为O(1)的缓存
JDK1.6“新“特性Instrumentation之JavaAgent(推荐)
before社区电量是什么意思 Before社区电量获得方法
网友评论