Spring简介
-
Spring 春天 给软件行业带来了春天
-
2002年,首次推出Spring框架的雏形:interface21框架
-
Spring框架即以interface21框架为基础,经过重新设计,并不断丰富其内涵,于2004年3月24日,发布了1.0正式版
-
Rod Johnson,Spring Framework创始人,著名作者。很难想象Rod Johnson的学历,真的让好多人大吃一惊,他是悉尼大学的博士,然而他的专业也不是计算机,而是音乐学。
-
spring理念:使现有的技术更加容易使用,本身是一个大杂烩,整合了现有的技术框架
-
SSH : Struct2 + Spring + Hiberanate
-
SSM : SpringMVC + Spring + Mybatis
Spring 优点
- Spring是一个开源的免费的框架
- Spring是一个轻量级、非入侵式的框架
- 控制反转(IOC) , 面向切面编程(AOP)
- 支持事务的处理,对框架整合的支持
Spring 就是一个轻量级的控制反转和面向切面编程的框架!
Spring组成
扩展
在Sping的官网有这个介绍:现代化的Java开发!说白就是基于Spring的开发
Spring Boot
- 一个快速开发的脚手架
- 基于SpringBoot可以快速的开发单个微服务
- 约定大于配置
SpringCloud - SpringCloud是基于SpringBoot实现的
弊端:发展了太久,违背了原本的理念!配置十分繁琐,人称:“配置地狱”
IOC理论推导
利用set进行动态实现值的注入
- 之前,程序是主动创建对象!控制权在程序员手上
- 使用set注入后,程序不再具有主动性,而是变成了被动的接受对象
这种思想,从本质上解决了问题,我们程序员不用再去管理对象的创建了。系统的耦合性大大降低,可以更加专注的在业务的实现上!这是IOC的原型!
控制:谁来控制对象的创建,传统应用程序的对象是由程序本身控制创建的,使用Spring后,对象是由Spring来创建的.
反转:程序本身不创建对象,而变成被动的接收对象.依赖注入:就是利用set方法来进行注入的.
IOC是一种编程思想,由主动的编程变成被动的接收.
可以通过newClassPathXmlApplicationContext去浏览一下底层源码.
OK,到了现在,我们彻底不用再程序中去改动了,要实现不同的操作,只需要在xml配置文件中进行修改,所谓的loC,一句话搞定:对象由Spring来创建,管理,装配!
IOC创建对象的方式
1.使用无参构造创建对象,默认!
2.假设我们要使用有参构造创建对象。
- 下标赋值
<bean id="user1" class="com.guantengyun.entity.User"><constructor-arg index="0" value="张三"/>
</bean>
- 类型赋值(不建议使用)
<bean id="user2" class="com.guantengyun.entity.User"><constructor-arg type="java.lang.String" value="张三"/>
</bean>
- 参数名赋值(常用)
<bean id="user3" class="com.guantengyun.entity.User"><constructor-arg name="name" value="lisi"/>
</bean>
总结:在配置文件加载的时候,容器中管理的对象就已经初始化了。
Spring配置
别名
<!-- 别名,如果添加了别名,也可以使用别名获取到这个对象 -->
<alias name="user1" alias="userNew"/>
Bean的配置
<!-- id:bean的唯一标识符,也就是相当于我们学的对象名class:bean 对象的全限定名 : 包名+类名name : 也是别名,而且name可以同时取多个别名 ,可以以空格、逗号、分号隔开scope默认为单例-->
<bean id="user1" class="com.guantengyun.entity.User" name="u1 uu1,uuu1;uuuu1"><constructor-arg index="0" value="张三"></constructor-arg>
</bean>
import
这个import,一般用于团队开发使用,可以将多个配置文件,导入合并为一个。
假设,现在项目中有多个人开发,这三个人复制不同的类开发,不同的类需要注册在不同的bean中,我们可以利用import将所有人的applicationContext.xml合并为一个总的!
<import resource="applicationContext2.xml"/>
<import resource="applicationContext3.xml"/>
<import resource="applicationContext4.xml"/>
使用的时候,直接使用总的配置就可以了
依赖注入
构造器注入
前面说过了
set方式注入【重点】
依赖注入:set注入!
package com.guantengyun.entity;
//地址类
public class Address {private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "Address [name=" + name + "]";}
}package com.guantengyun.entity;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
//学生类
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 String wife;private Properties info;public String getName() {return name;}public void setName(String name) {this.name = name;}public Address getAddress() {return address;}public void setAddress(Address address) {this.address = address;}public String[] getBooks() {return books;}public void setBooks(String[] books) {this.books = books;}public List<String> getHobbys() {return hobbys;}public void setHobbys(List<String> hobbys) {this.hobbys = hobbys;}public Map<String, String> getCard() {return card;}public void setCard(Map<String, String> card) {this.card = card;}public Set<String> getGames() {return games;}public void setGames(Set<String> games) {this.games = games;}public String getWife() {return wife;}public void setWife(String wife) {this.wife = wife;}public Properties getInfo() {return info;}public void setInfo(Properties info) {this.info = info;}@Overridepublic String toString() {return "Student [name=" + name + ", address=" + address + ", books=" + Arrays.toString(books) + ", hobbys="+ hobbys + ", card=" + card + ", games=" + games + ", wife=" + wife + ", info=" + info + "]";}
}
2.ApplicationContext.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-4.3.xsd"> <bean id="address" class="com.guantengyun.entity.Address"><property name="name" value="北京"></property></bean><bean id="student" class="com.guantengyun.entity.Student"><!-- 第一种,普通值注入,value --><property name="name" value="管腾运"></property><!-- 第二种,Bean注入,ref --><property name="address" ref="address"></property><!-- 数组 --><property name="books"><array><value>红楼梦</value><value>西游记</value><value>水浒传</value><value>三国演义</value></array></property><!-- list --><property name="hobbys"><list><value>听歌</value><value>敲代码</value><value>看电影</value></list></property><!-- Map --><property name="card"><map><entry key="身份证" value="12312312312312312332"></entry><entry key="银行卡" value="1111111111111111111111"></entry></map></property><!-- Set --><property name="games"><set><value>王者荣耀</value><value>刺激战场</value></set></property><!-- NULL --><property name="wife"><null/></property><!-- properties --><property name="info"><props><prop key="driver">18605182710</prop><prop key="url">男</prop><prop key="username">root</prop><prop key="password">root</prop></props></property></bean>
</beans>
3.测试类
package com.guantengyun.test;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.guantengyun.entity.Student;
public class MyTest {@Testpublic void test1() {ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");Student student = (Student) context.getBean("student");System.out.println(student);}
}
4.结果
Student [name=管腾运, address=Address [name=北京], books=[红楼梦, 西游记, 水浒传, 三国演义], hobbys=[听歌, 敲代码, 看电影], card={身份证=12312312312312312332, 银行卡=1111111111111111111111}, games=[王者荣耀, 刺激战场], wife=null, info={url=男, password=root, driver=18605182710, username=root}]
拓展方式注入
我们可以使用p命名空间和c命名空间进行注入
<?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:p="http://www.springframework.org/schema/p"xmlns:c="http://www.springframework.org/schema/c"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd"> <!-- p命名空间注入,可以直接注入属性的值:property --><bean id="user" class="com.guantengyun.entity.User" p:name="张三" p:age="18"/><!-- c命名空间注入,通过构造器注入:consturct-args --><bean id="user2" class="com.guantengyun.entity.User" c:name="李四" c:age="22"/>
</beans>
注意点:p命名和c命名不能直接使用,需要导入xml约束!
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
bean的作用域
1.单例模式(Spring默认机制)
<bean id="user2" class="com.guantengyun.entity.User" c:name="李四" c:age="22" scope="singleton"/>
2.原型模式:每次从容器中get的时候,都会产生一个新的对象
<bean id="user3" class="com.guantengyun.entity.User" c:name="李四" c:age="22" scope="prototype"/>
3.其余的request、session、application、这些个只能在web开发中使用到
Bean的自动装配
- 自动装配是Spring满足bean依赖一种方式!
- Spring会在上下文中自动寻找,并自动给bean装配属性!
在Spring中有三种装配的方式
1.在xml中显示的配置
2.在java中显示配置
3.隐式的自动装配bean [重要]
测试
环境搭建:一个人有两个宠物!
ByName自动装配
<bean id="cat" class="com.guantengyun.entity.Cat"></bean><bean id="dog" class="com.guantengyun.entity.Dog"></bean><!-- byName:会自动在容器上下文中查找,和自己对象set方法后面的值对应的beanid--><bean id="people" class="com.guantengyun.entity.People" autowire="byName"><property name="name" value="小慌神"></property></bean>
ByType自动装配
<bean class="com.guantengyun.entity.Cat"></bean><bean class="com.guantengyun.entity.Dog"></bean><!-- byType:会自动在容器上下文中查找,和自己对象属性类型相同的bean--><bean id="people2" class="com.guantengyun.entity.People" autowire="byType"><property name="name" value="小慌神"></property></bean>
小结:
- ByName的时候,需要保证所有的bean的id唯一,并且这个bean需要和自动注入的属性的set方法一致!
- ByType的时候,需要保证所有的bean的Class唯一,并且这个bean需要和自动注入的属性的类型一致!
使用注解实现自动装配
jdk1.5支持的注解,Spring 2.5支持的注解
要使用注解须知:
1、导入约束。context约束
2. 配置注解的支持 : context:annotation-config/
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:context="http://www.springframework.org/schema/context"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-4.3.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-4.3.xsd"><!-- 开启注解的支持 --><context:annotation-config /><bean id="cat" class="com.guantengyun.entity.Cat"></bean><bean id="dog" class="com.guantengyun.entity.Dog"></bean><bean id="people" class="com.guantengyun.entity.People"></bean></beans>
@Autowried
直接在属性上使用即可!也可以在set方法上使用!
使用Autowired我们可以不用编写set方法了,前提是这个自动装配的属性在IOC(Spring)中存在 ,且符合名字byname!
科普:
@Nullable //字段标记了这个注解,说明这个字段可以为null
public @interface Autowired{boolean required() default true;
}
测试代码
public class People{//如果显示定义了Autowired的required属性为false,说明这个对象可以为null,否则不允许为空@Autowired(required=false)private Cat cat;@Autowiredprivate Dog dog;private String name;
}
如果@Autowired自动装配的环境比较复杂,自动装配无法通过一个注解【@Autowired】完成的时候,我们可以使用@Qualifier(value=“xxx”)去配合@Autowired的使用,指定一个唯一的bean对象注入!
@Resource注解
@Resource(name="xxx") //通过name属性指定唯一的bean对象
小结:
@Autowired 和 @Resource区别:
- 都是用来自动装配的,都可以放在属性字段上
- @Autowired 通过bytype方式实现,而且必须要求这个对象存在!
- @Resource默认通过byname的方式实现,如果找不到名字,则通过byType实现,如果两个都找不到的情况下,就报错
- 执行顺序不同
使用注解开发
在Spring4之后,要使用注解开发,必须要保证aop的包导入了
使用注解需要导入context约束,增加注解的支持!
1、bean
@Component
2、属性如何注入
@Value(“xxx”)
3、衍生的注解
@Component有几个衍生注解,我们在web开发中,会按照mvc三层架构分层!
- dao 【@Repository】
- service【@Service】
- controller【@Controller】
这四个注解功能都是一样的,都是代表将某个类注册到Spring中,装配Bean
4、自动装配
@Autowired @Qualifier
@Resource
5、作用域
@Scope(“xxx”)
6、小结
xml和注解:
- xml更加万能,适用于任何场合!维护简单方便
- 注解 不是自己类使用不了,维护相对复杂!
xml与注解最佳实践:
- xml用来管理bean
- 注解只负责完成属性的注入
- 我们在使用的过程中,只需要注意一个问题:必须让注解生效,就需要开启注解的支持
<!-- 开启注解的支持 --><context:annotation-config /><!-- 指定要扫描的包,这个包下的注解就会生效 --><context:component-scan base-package="com.guantengyun.entity"/>
使用Java方式配置Spring
我们现在要完全不使用Spring的xml配置了,全权交给Java来做!
JavaConfig是Spring的一个子项目,在Spring4之后,它成为了一个核心功能!
实体类
package com.guantengyun.pojo;import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;@Component
public class User {@Value("管腾运")private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}
}
配置类(配置文件)
package com.guantengyun.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import com.guantengyun.pojo.User;
//这个也会被Spring托管,注册到容器中,因为它本来就是一个@Component
//代表这是一个配置类,相当于ApplicationContext.xml
@Configuration
@ComponentScan("com.guantengyun.pojo") //扫描包
@Import(UserConfig2.class)
public class UserConfig {//注册一个bean,相当于bean标签//方法的名字,相当于bean标签的id属性//方法的返回值,相当于bean标签的Class属性@Beanpublic User getUser() {return new User(); //就是返回要注入到bean的对象}
}
测试类
package com.guantengyun.test;import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.guantengyun.config.UserConfig;
import com.guantengyun.pojo.User;public class MyTest {public static void main(String[] args) {//如果完全使用了配置类的方式去做,我们只能通过 AnnotationConfig 上下文来获取容器,通过配置类的class对象加载!ApplicationContext context = new AnnotationConfigApplicationContext(UserConfig.class);User user = context.getBean("getUser",User.class);String name = user.getName();System.out.println("用配置类配置:"+name);}
}
这种纯Java的配置方式,在SpringBoot中随处可见!