Spring入门学习
一、Spring
1.1、简介
-
Spring:春天------>给软件行业带来了春天!
-
2002,首次推出了Spring框架的雏形: interface21框架!
-
Spring框架即以interface21框架为基础,经过重新设计;并不断丰富其内涵,于2004年3月24日,发布了1.0正式版。
-
Rod Johnson ,Spring Framework创始人,著名作者。
-
spring理念:使现有的技术更加容易使用,本身是一个大杂烩,整合了现有的技术框架!
SSH : Struct2 + Spring +Hibernate!
SSM : SpringMvc + Spring + Mybatis! -
官网:https://lspring.io/projects/spring-framework#overview
-
官方下载地址: http://repo.spring.io/release/org/springframework/spring
-
GitHub: https://github.com/spring-projects/spring-framework
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
1.2、优点
- Spring是一个开源的免费的框架(容器)!
- Spring是一个轻量级的、非入侵式的框架!
- 控制翻转(IOC),面向切面编程(AOP)
- 支持事务的处理,对框架整合的支持!
总结一句话: Spring就是一个轻量级的控制反转(IOC)和面向切面(AOP)编程的框架!
1.3、组成
1.4、拓展
在spring的官网有这个介绍,现代化的java开发!说白就是基于spring的开发
- springBoot
- 一个快速开发的脚手架
- 基于SpringBoot可以快速的开发单个微服务
- 约定大于配置
- SpringCloud
- SpringCloud是基本SpringBoot
因为现在大多数公司都在使用SpringBoot进行快速开发,学习SpringBoot的前提,需要完全掌握Spring及SpringMVC!承上启下的作用!
弊端:发展了太久之后,违背原来的理念!配置十分繁琐,人称:”配置地狱!“
二、IOC理论推导
2.1、环境搭建及简单实现
1.UserDao接口
2.UserDaolmpl实现类
3.UserService 业务接口
4.UserServicelmpl 业务实现类
2.2、实现一个IOC
在我们之前的业务中,用户的需求可能会影响我们原来的代码,我们需要根据用户的需求去修改原代码!如果程序代码量十分大,修改一次的成本代价十分昂贵!
我们使用一个Set接口实现.
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
- 之前都是程序主动创建对象,控制权在程序员手里
- 使用set注入之后,程序不再具有主动性 ,而变成了被动的接受对象!
这种思想,从本质上解决了问题,我们程序猿不用再去管理对象的创建了。系统的耦合性大大降低~,可以更加专注的在业务的实现上!
基础实现:
//用户实际调的是业务层,Dao层他们不需要接触
UserService userService =new UserServiceImpl();
userService.setUserDao(new UserDaoMysqImpl());
userService.getUser();
采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,
Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。
**控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是loC容器,其实现方法是依赖注入(Dependency Injection,Dl) 。**I
<! --使用Spring米创建对象,在Spring这些都称为Bean
类型 变量名 = new类型();
Hello hello = new HelLo( );
id =变量名
class = new的对象;
property相当于给对象中的属性设置一个值!-->
2.3、思考问题?
-
Hello对象是谁创建的?
hello 对象是由Spring创建的 -
Hello对象的属性是怎么设置的?
hello 对象的属性是由Spring容器设置的,这个过程就叫控制反转:
控制:谁来控制对象的创建,传统应用程序的对象是由程序本身控制创建的,使用Spring后,对象是由Spring来创建的.
反转∶程序本身不创建对象,而变成被动的接收对象
依赖注入:就是利用set方法来进行注入的
IOC是一种编程思想,由主动的编程变成被动的接收
可以通过newClassPathXmlApplicationContext去浏览一下底层源码
OK,到了现在,我们彻底不用再程序中去改动了,要实现不同的操作,只需要在xml配置文件中进行修改,所谓的loc,一句话搞定:对象由Spring 来创建,管理,装配!
2.4、控制翻转IOC简单实例:
<bean id="UserDaoImpl" class="com.LH.Dao.UserDaoImpl"/>
<bean id="UserDaoMysqImpl" class="com.LH.Dao.UserDaoMysqImpl"/>
<bean id="UserServiceImpl" class="com.LH.service.UserServiceImpl">
<property name="userDao" ref="UserDaoMysqImpl"/>
</bean>
//获取ApplicationContext,拿到Spring容器
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//容器在手,天下我有,用什么都用get取就完事
UserServiceImpl userServiceImpl = (UserServiceImpl) context.getBean("UserServiceImpl");
userServiceImpl.getUser();
System.out.println(userServiceImpl);
三、IOC创建对象的方式
3.1、使用无参构造创建对象,默认
<bean id="user" class="com.LH.pojo.User">
<property name="name" value="文静"/>
</bean>
public User() {
System.out.println("使用无参构造方法");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void show(){
System.out.println("name"+name);
}
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
User user = (User) context.getBean("user");
user.show();
}
结果:
使用无参构造方法
name文静
3.2、使用有参构造构造对象
1.下标赋值
<bean id="user" class="com.LH.pojo.User">
<!-- 下标赋值-->
<constructor-arg index="0" value="文静"/>
</bean>
2.类型
<!--类型赋值 不建议使用-->
<constructor-arg type="java.lang.String" value="文静"/>
3.参数名(掌握)
<!--直接通过参数名-->
<constructor-arg name="name" value="文静"/>
注意:在配置文件加载的时后,spring容器中的对象就已经被初始化了
四、spring配置
4.14、别名 alias
<!--别名,添加了别名,也可以使用别名获取对象-->
<alias name="user" alias="userNew"/>
4.2、bean
<!--
id : bean 的唯一标识符,也就是相当于我们学的对象名
cLass : bean对象所对应的全限定名:包名+类型
name :也是别名,而且iname 可以同时取多个别名
-->
<bean id="userT" class="com.kuang.pojo.UserT" name="user2 u2,u3;u4">
<property name="name" value="西部开源"/>
</bean>
4.3、import
多用于团队开发使用,他可以将多个配置文件,导入合并到一个
假设现有多人开发,每个人开发不同的类,不同的类需要注册在不同的bean中,我们可以利用import将所有的bean.xml合并为一个总得
- bean.xml
- bean2.xml
- bean3.xml
- ApplicationContext.xml
<import resource="bean2.xml"/>
<import resource="bean3.xml"/>
<import resource="beans.xml"/>
使用时使用总的配置ApplicationContext.xml就可以了
五、依赖注入
5.1、构造器注入
已经说过了
5.2、set注入!【重点】
- 依赖注入:set注入
- 依赖:bean对象的创建依赖于容器
- 注入:bean对象的所有属性,由容器来注入
【环境搭建】
1.复杂类型
package com.LH.pojo;
public class Address {
private String address;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
2.真实测试对象
public class Student {
private String name;
private Address address;
private String[] books;
private List<String> hobbys;
private Map<String,String> card;
private Set<String> games;
private Properties info;
private String wife;
3.beans.xml
<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">
<!--第一种使用普通值注入,vlue-->
<bean id="student" class="com.LH.pojo.Student">
<property name="name" value="猪猪猪"/>
</bean>
</beans>
4.测试
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
Student student = (Student) context.getBean("student");
System.out.println(student.getAddress());
}
}
5.完善注册
<bean id="address" class="com.LH.pojo.Address">
<property name="address" value="四川"/>
</bean>
<bean id="student" class="com.LH.pojo.Student">
<!--第一种使用普通值注入,vlue-->
<property name="name" value="猪猪猪"/>
<!--bean注入,ref-->
<property name="address" ref="address"/>
<!--数组-->
<property name="books">
<array>
<value>世界那么大我想去看看</value>
<value>C++从入门到精通</value>
<value>考研英语2020</value>
</array>
</property>
<!--List-->
<property name="hobbys">
<list>
<value>唱歌</value>
<value>画画</value>
<value>吃饭</value>
</list>
</property>
<!--Map-->
<property name="card">
<map>
<entry key="身份证" value="510xxxxxxxxxxxxxxxx"/>
<entry key="银行卡" value="155465464564654651"/>
</map>
</property>
<!--Set-->
<property name="games">
<set>
<value>王者荣耀</value>
<value>LOL</value>
<value>COC</value>
</set>
</property>
<!--null-->
<property name="wife">
<null/>
</property>
<!--Properties-->
<property name="info">
<props>
<prop key="driver">小明</prop>
<prop key="url">201812345678</prop>
<prop key="username">root</prop>
<prop key="password">151212</prop>
</props>
</property>
</bean>
5.3拓展方式注入
使用p命名和c命名空间进行注入
官方解释:
使用:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--p命名空间注入,可以直接注入属性的值:peoperties-->
<bean id="user" class="com.LH.pojo.User" p:name="猪猪" p:age="21"/>
<!--c命名空间注入,可以通过构造器注入construct-->
<bean id="user2" class="com.LH.pojo.User" c:name="猪猪2" c:age="18 "/>
</beans>
测试:
@Test
public void Test(){
ApplicationContext context = new ClassPathXmlApplicationContext("UserBean.xml");
User user = context.getBean("user2", User.class);
System.out.println(user);
}
注意点:
p命名和c命名不能直接使用需要导入配置文件
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
5.4、Bean的作用域
1.单例模式:(Spring默认的)
<bean id="user2" class="com.LH.pojo.User" c:name="猪猪2" c:age="18" scope="singleton"/>
2.原型模式:每次从容器中get的时候,都会产生一个新的对象
<bean id="user2" class="com.LH.pojo.User" c:name="猪猪2" c:age="18" scope="prototype"/>
3.其余的 request,session,application只能在web开发中使用!
六、Bean的自动装配
- 自动装配是Spring满足Bean依赖的一种方式
- Spring会在上下文中自动寻找,并自动给Bean装配属性
spring中有三种装配方式
- 在xml中显示配置
- 在java中显示配置
- 隐式的自动装配bean
6.1、测试
环境搭建:一个人有两个宠物!
6.2、ByName的自动装配
<!--
byname:会自动在容器上下文中查找,和自己对象set方法后面的值对应的beanid!
-->
<bean id="people" class="com.LH.pojo.People" autowire="byName">
<property name="name" value="猪猪"/>
</bean>
6.3、ByType
<bean class="com.LH.pojo.Cat"/>
<bean id="pig123" class="com.LH.pojo.Pig"/>
<!--
byName:会自动在容器上下文中查找,和自己对象set方法后面的值对应的beanid!
byType:会自动在容器上下文中查找,和自己对象属性类型(class)相同的bean!
-->
<bean id="people" class="com.LH.pojo.People" autowire="byType">
<property name="name" value="猪猪"/>
</bean>
6.4、小结:
- 使用ByName的时候,需要保证所有的bean的id唯一,并且这个bean需要和自动注入的属性的set方法的值一致!
- 使用ByType的时候,需要保证所有的bean的class唯一,并且这个bean需要和自动注入的属性的类型一致!id可以省略不写
6.5、 使用注解自动装配
jdk1.5支持注解,spring2.5支持注解
要使用注解须知:
1.导入约束:context
2.配置注解支持: context:annotation-config/
<?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:annotation-config/>
</beans>
@Autowired
直接在属性上使用即可! 也可以在set方式上使用!
使用Autowired我们可以不用编写Set方法了,前提是你这个自动装配的属性在IOC (Spring)容器中存在,且符合名字byType!
@Autowired
private Cat cat;
@Autowired
private Pig pig;
private String name;
<bean id="cat" class="com.LH.pojo.Cat"/>
<bean id="pig" class="com.LH.pojo.Pig"/>
<bean id="people" class="com.LH.pojo.People"/>
如果@Autowired自动装配的环境比较复杂,自动装配无法通过一个注解【@Autowired】完成的时候、我们可以使用@Qualifier(value=“xxx”)去配合@Autowired的使用,指定一个唯一的bean对象注入!
@Autowired
@Qualifier(value ="cat2")
private Cat cat;
@Autowired
@Qualifier(value ="pig22")
private Pig pig;
private String name;
<bean id="cat1" class="com.LH.pojo.Cat"/>
<bean id="cat2" class="com.LH.pojo.Cat"/>
<bean id="pig1" class="com.LH.pojo.Pig"/>
<bean id="pig22" class="com.LH.pojo.Pig"/>
<bean id="people" class="com.LH.pojo.People"/>
@Resource注解:
@Resource(name = "cat2")
private Cat cat;
@Resource(name = "pig22")
private Pig pig;
private String name;
小结:@Resource和@Autowired区别
@Resource默认按 byName自动注入罢了。@Resource有两个属性是比较重要的,分是name和type,Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。所以如果使用name属性,则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略。如果既不指定name也不指定type属性,这时将通过反射机制使用byName自动注入策略。
@Resource装配顺序
1. 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常
2. 如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常
3. 如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常
4. 如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配;
@Autowired 与@Resource的区别:
1、 @Autowired与@Resource都可以用来装配bean. 都可以写在字段上,或写在setter方法上。
2、 @Autowired默认按类型装配(这个注解是属业spring的),默认情况下必须要求依赖对象必须存在,如果要允许null值,可以设置它的required属性为false,如:@Autowired(required=false) ,如果我们想使用名称装配可以结合@Qualifier注解进行使用,如下:
@Autowired()@Qualifier("baseDao")
private BaseDao baseDao;
3、@Resource(这个注解属于J2EE的),默认按照名称进行装配,名称可以通过name属性进行指定,如果没有指定name属性,当注解写在字段上时,默认取字段名进行安装名称查找,如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。
@Resource(name="baseDao")
private BaseDao baseDao;
推荐使用:@Resource注解在字段上,这样就不用写setter方法了,并且这个注解是属于J2EE的,减少了与spring的耦合。这样代码看起就比较优雅。
七、使用注解开发
在spring4之后,要使用注解开发,就必须要保证aop的包导入了
使用注解一定要导入context约束,增加注解的支持!
7.1、bean
7.2、属性如何注入
// @Value组件等价于 <property name="name" value="猪猪"/>
@Component
public class User {
@Value("猪猪")
String name;
//也可以直接放在方法上面
@Value("猪猪2")
public void setName(String name) {
this.name = name;
}
7.3、衍生的注解
@component有几个衍生注解,我们在web开发中,会按照mvc三层架构分层
- dao 【@Repository】
- serviceo 【@Service】
- controller 【@Controller】
这四个注解功能都是一样的,都是代表将某个类注册到Spring中,装配Bean
7.4、自动装配置
@Autowired :自动装配通过类型,名字
如果Autowired 不能唯一自动装配上属性,则需要通过@Qualifier(value=“xxx”)
@Nullable 字段标记了这个注解,说明这个字段可以为nu77;
@Resource:自动装配通过名字,类型
7.5、作用域
@Scope
7.6、小结
xml与注解:
- xml 更加万能,适用于任何场 合!维护简单方便
- 注解不是自己类使用不了,维护相对复杂!
- xml与注解最佳实践:
- xml用来管理bean
- 注解只负责完成属性的注入
- 我们在使用的过程中,只需要注意一个问题,必须让注解生效,需要开启注解支持
<!--指定要扫描的包,这个包下的注解就会生效-->
<context:component-scan base-package="com.LH"/>
<!--注解支持-->
<context:annotation-config/>
7.3、衍生的注解
@component有几个衍生注解,我们在web开发中,会按照mvc三层架构分层
- dao 【@Repository】
- serviceo 【@Service】
- controller 【@Controller】
这四个注解功能都是一样的,都是代表将某个类注册到Spring中,装配Bean
7.4、自动装配置
@Autowired :自动装配通过类型,名字
如果Autowired 不能唯一自动装配上属性,则需要通过@Qualifier(value=“xxx”)
@Nullable 字段标记了这个注解,说明这个字段可以为nu77;
@Resource:自动装配通过名字,类型
7.5、作用域
@Scope
7.6、小结
xml与注解:
- xml 更加万能,适用于任何场 合!维护简单方便
- 注解不是自己类使用不了,维护相对复杂!
- xml与注解最佳实践:
- xml用来管理bean
- 注解只负责完成属性的注入
- 我们在使用的过程中,只需要注意一个问题,必须让注解生效,需要开启注解支持
<!--指定要扫描的包,这个包下的注解就会生效-->
<context:component-scan base-package="com.LH"/>
<!--注解支持-->
<context:annotation-config/>