Spring
1,什么是Spring?
Spring 显而易见英文单词:春天 的意思
2002年,Rod Jahnson首次推出了Spring框架雏形interface21框架。
2004年3月24日,Spring框架以interface21框架为基础,经过重新设计,发布了1.0正式版。
官网 : http://spring.io/
官方下载地址 : https://repo.spring.io/libs-release-local/org/springframework/spring/
GitHub : https://github.com/spring-projects
同样也可以使用maven引入依赖
<!--spring依赖的引入-->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.23</version>
</dependency>
</dependencies>
2,Spring的优点是什么?
1、Spring是一个开源免费的框架 , 容器 .
2、Spring是一个轻量级的框架 , 非侵入式的 .
3、控制反转 IOC , 面向切面 Aop
4、对事物的支持 , 对框架的支持
总而言之Spring是一个轻量级的控制反转(IOC)和面向切面(AOP)的容器(框架)。
详细介绍可以看官方文档
3,SpringIOC的详细介绍
从上面可以看出Spring的优点很多,但是对于其核心IOC与AOP可能有人还不是很清楚什么是IOC什么是AOP
那么接下来我们就来看一下IOC
什么是IOC?
控制反转(IOC),那么什么是控制反转呢?控制反转是一种设计思想,DI(依赖注入)是实现IOC的一种方法,也有人认为DI只是IOC的另一种说法。没有IOC的程序中 , 我们使用面向对象编程 , 对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,个人认为所谓控制反转就是:获得依赖对象的方式反转了。
如何理解好IOC呢?说白了Ioc的关键是要明确“谁控制谁,控制什么,为何是反转(有反转就应该有正转了),哪些方面反转了”
为什么要有IOC?
代码书写现状:耦合度太高,我们修改一处代码,往往要修改很多出相关联的代码。
比如我们有一个功能是获取用户数据,我们使用Dao层实现这个功能,再在Service层调用这个功能。但是我们每增加一个接口,比如获取mysql中的数据,就要修改原来的代码,如果再增加一个新的接口,又需要去service实现类中修改对应的实现。
解决方法:我们在创建对象的时候,不自己创建而是由外部提供对象
因此出现了IOC 对象的创建权由程序转移到外部,这种思想叫做控制反转。
IOC的核心概念
- 使用对象时候由主动new对象转换成由外部提供对象,此过程中对象的创建权由程序转移到外部,这种思想叫做控制反转
- Spring技术对此提供的实现
- Spring提供了一个容器,称为IOC容器,用来充当IOC思想中的外部
- IOC容器负责对象的创建、初始化等一系列工作,被创建或被管理的对象在IOC容器中统称为Bean。
IOC的实现主要依靠DI依赖注入 在容器中建立bean与bean之间的依赖关系
而DI依赖注入的方式也分很多
DI依赖注入方式
我们根据bean.xml中bean对象中属性的添加方式 对应不同依赖注入方式,在某个bean中其可能需要用到其他实体类作为属性,那么此时也不用自己new,IOC容器给你提供,那么如何提供呢?那就是这个bean你得给IOC容器一个入口 即 set方法 或者构造器方法
1,set方式注入
Dao层
public class UserDao {
public void test(){
System.out.println("UserDao Test....");
}
}
Service层
/**
* Set方法注入
* 1,属性字段提供set方法
* 2,在配置文件中通过property属性指定属性字段
* */
public class UserService {
//手动实例化
// UserDao userDao=new UserDao();
//业务逻辑对象 JavaBean对象 set方法注入
//JavaBean对象
private UserDao ud;
public void setUd(UserDao ud) {
this.ud = ud;
}
//常用对象(日期类型,String对象)
private String host;
public void setHost(String host) {
this.host = host;
}
//基本对象
private Integer port;
public void setPort(Integer port) {
this.port = port;
}
//List集合
private List<String> list;
public void setList(List<String> list) {
this.list = list;
}
public void printList(){
list.forEach(n -> System.out.println(n));
}
//Set集合
private Set<String> set;
public void setSet(Set<String> set) {
this.set = set;
}
public void printSet(){
set.forEach(n -> System.out.println(n));
}
//Map集合
private Map<String,Object> map;
public void setMap(Map<String, Object> map) {
this.map = map;
}
public void printMap(){
map.forEach((k,v) -> System.out.println(k+"---"+v));
}
//properties属性对象
private Properties properties;
public void setProperties(Properties properties) {
this.properties = properties;
}
public void printproperties(){
properties.forEach((k,v) -> System.out.println(k+"---"+v));
}
public void test(){
System.out.println("UserService Test....");
ud.test();
//常用对象
System.out.println(host);
//基本类型
System.out.println(port);
//List集合
printList();
//Set集合
printSet();
//Map集合
printMap();
//porperties属性对象
printproperties();
}
}
相关spring.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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
Set方法注入
通过property属性注入
name:bean对象中属性字段的名称
ref:指定bean标签的id属性值
-->
<bean id="userService" class="com.xxxx.service.UserService">
<!-- JavaBean对象注入-->
<property name="ud" ref="userDao"/>
<!-- 常用对象string注入-->
<property name="host" value="127.0.0.1"/>
<!-- 基本类型注入-->
<property name="port" value="8080"/>
<!-- List集合-->
<property name="list">
<list>
<value>北京</value>
<value>上海</value>
<value>广州</value>
</list>
</property>
<!-- Set集合-->
<property name="set">
<set>
<value>北京BJ</value>
<value>上海SH</value>
<value>广州GZ</value>
</set>
</property>
<!-- Map集合-->
<property name="map">
<map>
<entry>
<key><value>周杰伦</value></key>
<value>青花瓷</value>
</entry>
<entry>
<key><value>周深</value></key>
<value>大鱼海棠</value>
</entry>
<entry>
<key><value>林俊杰</value></key>
<value>JJ</value>
</entry>
</map>
</property>
<!-- properties属性对象-->
<property name="properties">
<props>
<prop key="ds">屌丝</prop>
<prop key="hhh">哈哈哈</prop>
<prop key="cj">菜鸡</prop>
</props>
</property>
</bean>
<bean id="userDao" class="com.xxxx.dao.UserDao"></bean>
</beans>
测试
public class starter01 {
public static void main(String[] args) {
ApplicationContext ac=new ClassPathXmlApplicationContext("spring.xml");
UserService userService= (UserService) ac.getBean("userService");
userService.test();
}
}
我们先通过获取到的IOC容器,然后再通过IOC容器获取到Bean,然后底层是通过反射创建这个bean对象,然后这个bean当中可能存在一些依赖关系,那么的话这个时候IOC容器会调用set方法对这些属性进行注入。
2,构造器注入
属性的添加方式是 constructor
Dao层
public class UserDao02 {
public void test(){
System.out.println("UserDao02 Test....");
}
}
Service层
/**
* 构造器方法注入
* 必须含有构造方法
* */
public class UserService02 {
private UserDao02 userDao02;
// public UserService02(UserDao02 userDao02) {
// this.userDao02 = userDao02;
// }
private Integer age;
public UserService02(UserDao02 userDao02, Integer age) {
this.userDao02 = userDao02;
this.age = age;
}
public void test(){
System.out.println("UserService02 Test....");
userDao02.test();
}
}
相关spring.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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
构造器方法注入
设置构造器所需的参数
通过constructor-arg标签设置构造器的参数
构造器中有几个参数就要设置几个
name:UserService02中定义的属性名称
ref:要注入的bean对象对应的bean标签id属性值
value:数据具体值
index:参数的位置
如果出现 循环依赖问题只有通过set方法注入
-->
<bean id="userService02" class="com.xxxx.service.UserService02">
<constructor-arg name="userDao02" ref="userDao02"></constructor-arg>
<constructor-arg name="age" value="18"></constructor-arg>
</bean>
<bean id="userDao02" class="com.xxxx.dao.UserDao02"></bean>
</beans>
测试
public class starter02 {
public static void main(String[] args) {
ApplicationContext ac=new ClassPathXmlApplicationContext("spring02.xml");
UserService02 userService02= (UserService02) ac.getBean("userService02");
userService02.test();
}
}
我们通过构造器注入这个属性,我们配置文件中将Dao这个属性的添加方式提供了,那么接下来就是IOC容器调用构造方法将bean.xml文件中的属性注入到相关service
依赖的自动装配
- 概念:IOC容器根据bean所依赖的资源在容器中自动查找 并注入到bean的过程叫做 自动装配
- bean.xml 那么这个里头的话 我们就不要再写 property 因为我们是自动查找依赖 一般使用的是按类型
<!-- 配置bean对象-->
<bean id="userService" class="com.xxxx.service.UserService"></bean>
<bean id="userDao" class="com.xxxx.dao.UserDao" ></bean>
自动装配注意事项
自动装配用于引用类型依赖注入,不能对简单类型进行操作
使用按类型装配时(byType)必须保障容器中相同类型的bean唯一,推荐使用
使用按名称装配时(byName)必须保障容器中具有指定名称的bean,因变量名与配置耦合,不推荐使用
自动装配优先级低于setter注入与构造器注入,同时出现时自动装配配置失效
注解开发模式的依赖注入
Dao层:
@Repository
service层:
@Service
controller层:
@Controller
其他层:
@Component
IOC容器就会扫描容器中的bean
@Autowired 或 @Resource
一个实例带你将快速了解注解模式
controller层
@Controller
public class TypeController {
@Resource
private TypeService typeService;
public void test(){
System.out.println("TypeController ....");
typeService.test();
}
}
service层
@Service
public class TypeService {
@Resource
private TypeDao typeDao;
public void test(){
System.out.println("TypeService Test....");
typeDao.test();
}
}
dao层
@Repository
public class TypeDao {
public void test(){
System.out.println("TypeDao Test....");
}
}
spring02.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">
<!--
Spring IOC扫描器
作用:bean对象的统一管理,简化开发配置,提高效率
1,设置自动化扫描范围
如果bean对象在扫描范围可以生效,否则无效
2,在需要被实例化的JavaBean的类上添加注解(注解声明在类级别) (bean对象 的id属性默认是 类的首字母小写)
Dao层:
@Repository
service层:
@Service
controller层:
@Controller
其他层:
@Component
注:开发过程中建议按照规则声明注解
-->
<!-- 设置自动化扫描的范围-->
<context:component-scan base-package="com.xxxx"/>
</beans>
测试
public class App02
{
public static void main( String[] args ) {
ApplicationContext ac=new ClassPathXmlApplicationContext("spring02.xml");
TypeController typeController= (TypeController) ac.getBean("typeController");
typeController.test();
}
}