Spring
核心技术点: ioc di aop 声明式事务
ioc的底层实现(理解)
spring提供的ioc技术帮助我们解决了程序的高耦合问题,让我们不再花费时间去关心程序的高耦合
- 耦合关系
耦合:在编程语言中,就是计算机代码之间的依赖关系
代码之间的依赖关系如果很高就意味着程序高耦合,不利于后期项目的扩展开发,因此我们需要给程序松耦合
高耦合—松耦合–低耦合
需求 :自定义ioc的代码,实现更加松耦合的程序
代码实现:
- webTest
public class webTest {
@Test
public void test2() throws Exception {
UserService userService1= (UserService) Factory2.getBean("userService");
System.out.println(userService1);
}
}
- 单例工厂
package cn.itcast.utils;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;
//单例工厂模式
public class Factory2 {
private static ResourceBundle bundle=null;
private static Map<String,Object> map=new HashMap();
static {
try {
//反射创建对象
//只要加载后缀名为properties的文件 统一用ResourceBundle 不能加载xml 底层写死了后缀名
bundle=ResourceBundle.getBundle("bean");
//获取所有的key
Enumeration<String> keys = bundle.getKeys();
while (keys.hasMoreElements()){
//获取key aaa
String key = keys.nextElement();
//cn.itcast.service.impl.UserServiceImpl--对象
String value = bundle.getString(key);
Class clazz = Class.forName(value);
Object obj = clazz.newInstance();
map.put(key,obj);
}
}catch (Exception e){
e.printStackTrace();
}
}
public static Object getBean(String id) throws Exception {
Object obj = map.get(id);
return obj;
}
}
4)多例工厂
package cn.itcast.utils;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;
//多例工厂模式
public class Factory {
private static ResourceBundle bundle=null;
private static Map<String,Object> map=new HashMap();
static {
//反射创建对象
//只要加载后缀名为properties的文件 统一用ResourceBundle 不能加载xml 底层写死了后缀名
bundle=ResourceBundle.getBundle("bean");
//获取所有的key
Enumeration<String> keys = bundle.getKeys();
while (keys.hasMoreElements()){
//获取key aaa
String key = keys.nextElement();
//cn.itcast.service.impl.UserServiceImpl
String value = bundle.getString(key);
map.put(key,value);
}
}
public static Object getBean(String id) throws Exception {
String value =(String) map.get(id);
Class clazz = Class.forName(value);
Object obj = clazz.newInstance();
return obj;
}
}
5)UserService
public interface UserService {
}
- UserServiceImpl
public class UserServiceImpl implements UserService {
}
- application.xml
<beans>
<bean id="userService" class="cn.itcast.serviceImpl.UserServiceImpl"></bean>
</beans>
结论
通过以上的配置文件+反射+工厂的方式可以实现程序解耦合,而spring的底层封装的就类似这一套的实现(ioc)
一 认识Spring的ioc容器
ioc:控制反转
指的是对象的控制权由原来开发者在类中自己手动创建控制 反转到 由Spring/ioc容器创建控制
其实spirng底层已经做好了工厂,这个工厂就已经帮助我们创建好了对象,放入到ioc容器中(就是map集合)
ioc作用
帮助咱们创建管理对象,做到程序之间的解耦合
获取对象方式:
传统方式获取对象:主动出击 new
Spring方式获取对象:问ioc容器要对象
二 Spring概述【了解】
Spring是分层的 Java SE/EE应用 full-stack 开源框架。以 IOC(Inverse Of Control:控制反转)和 AOP(Aspect Oriented Programming:面向切面编程)为内核。
简单说:spring为三层开发提供了一站式的解决方案
web层: servlet---->springMvc框架
service层:声明式事务 --->事务
dao层:jdbc---->jdbcTemplate (企业多用mybits)
友情提示 spring课程的学习侧重点:ioc技术(DI) aop技术 声明式事务技术
spring的体系结构图
三 Spring的ioc快速入门【重点】
环境搭建
1 导入依赖
spring坐标依赖 要求junit4.12及以上版本
2 将对象的创建和管理交给spring容器
xml配置文件
3 从spring容器中获取对象
java代码的API调用
1)spring的依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
- Demo2
public class Demo2 {
public static void main(String[] args) {
// 创建ioc容器管理对象
ApplicationContext context=new ClassPathXmlApplicationContext("application.xml");
// 问ioc容器要对象
UserService userService =(UserService)context.getBean("userService");
userService.save();
}
}
- application.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">
<!--
id:唯一标识名(整个xml下唯一)
class:类的全限定名
-->
<bean id="userService" class="cn.itcast.serviceImpl.UserServiceImpl"></bean>
</beans>
流程图
四 Spring相关API【理解】
实现类
* FileSystemXmlApplicationContext【了解】
功能:从指定磁盘目录加载xml配置文件,创建spring的ioc容器
------------------------------------------
* ClassPathXmlApplicationContext (加载配置文件的)
功能:从类路径下加载xml配置文件,创建spring的ioc容器
* AnnotationConfigApplicationContext (加载注解的)
功能:加载注解配置类,创建spring的ioc容器
方法
1. public Object getBean(String id) throws BeansException; (掌握)
功能:通过指定id获取对象的实例,需要手动强转
2. public <T> T getBean(Class<T> requiredType);
功能:通过指定类型获取对象的实例,不需要强转
注意:同一个类型下只能有一个对象实例
五 Spring配置文件【重点】
5.1 Bean标签
配置信息
bean标签:指定创建对象的
id属性:唯一标识(配置文件中唯一)
class属性:实现类的全限定名
scope属性:范围
取值:singleton(单例默认) prototype(多例) 扩展:request,session,globesession..
singleton:对象是随着容器的创建而创建 随着容器的销毁而销毁 自始至终只有一个对象
prototype:对象的创建和销毁与容器的创建和销毁无关
每次执行getBean的时候创建新的对象 调用一次创建一次
销毁是会等待垃圾回收机制自动完成的
init-method属性: 对象创建之后指定调用方法
destroy-method属性:对象销毁后指定调用方法
5.2 spring创建对象实例三种方式
1.构造方式(重要)
2.静态工厂: 该工厂中获取对象的方法是静态的 可以类名直接调用(了解)
3.实例化工厂:该工厂中获取对象的方法是非静态的 必须得有工厂对象才能调用方法(了解)
1)构造方法实例化【重点】
<!--
构造方法实例化
底层使用的是构造器创建对象
-->
<bean id="userService" class="cn.itcast.serviceimpl.UserServiceImpl"></bean>
2)工厂静态方法实例化【了解】
/**
* 工厂静态方法实例化
*/
public class Factory {
public static Object getBean(){
return new UserServiceImpl();
}
}
<!--
工厂静态方法实例化
class="cn.itcast.utils.Factory" 工厂全限定类名
factory-method="getBean" 创建userService对象的静态方法
-->
<bean id="userService" class="cn.itcast.utils.Factory" factory-method="getBean"></bean></bean>
3)工厂普通方法实例化【了解】
/**
* 工厂普通方法实例化
*/
public class Factory2 {
public Object getBean(){
return new UserServiceImpl();
}
}
<!--
工厂普通方法实例化
先实例化工厂
<bean id="factory" class="cn.itcast.utils.Factory2"></bean>
再调用方法创建userService对象
<bean id="userService" factory-bean="factory" factory-method="getBean"></bean>
factory-bean="factory" 告诉spring容器从哪个工厂来创建实例
-->
<bean id="factory" class="cn.itcast.utils.Factory2"></bean>
<bean id="userService" factory-bean="factory" factory-method="getBean"></bean>
六 Bean依赖注入概述(掌握)
依赖注入(Dependency Injection):它是 Spring 框架核心 IOC 的具体实现。
在编写程序时,通过控制反转,把对象的创建交给了 Spring,但是对象的属性应该如何管理,这里spring
提供了技术:依赖注入
依赖注入:对存在依赖关系的属性或者对象自动赋值
属性分类:
注入简单数据类型的数据
注入复杂类型的数据(单列(array,list,set)和 双列(map,properties对象))
注入被spring容器管理的对象
依赖注入的两种方式:构造方法注入和set方法注入
Bean依赖注入方式
1)构造方法注入(了解)
public class UserServiceImpl implements UserService {
/*
* spring除了提供了ioc容器用来创建管理对象
* 也提供了一个技术可以用来给对象的各种属性赋值:依赖注入(DI)
* 对象的属性:
* 简单属性:string interger double...(了解)
* 对象属性:userDao(掌握)
* 复杂属性: 数组 list set 单列 | map properties 双列(掌握)
* 依赖注入(di):构造器方式赋值(了解) set属性方式赋值(掌握--用它)
*
* */
// 简单属性
private String name;
private Integer age;
// 构造器方式
public UserServiceImpl(String name, Integer age) {
this.name = name;
this.age = age;
}
@Override
public void save() {
System.out.println(name+":"+age);
}
// 对象属性
private UserDao userDao;
// 构造器方式
public UserServiceImpl(UserDao userDao) {
this.userDao = userDao;
}
public void save() {
userDao.save();
}
}
<!-- dao -->
<bean id="userDao" class="cn.itcast.daoimpl.UserDaoImpl"></bean>
<!--service -->
<bean id="userService" class="cn.itcast.serviceimpl.UserServiceImpl">
<!--构造器的属性赋值
constructor-arg标签
属性:
index:数组角标的方式定位属性
name: 属性名的方式定位属性
type: 属性的全限定名类型定位属性
*****以上三种是用来定位属性的
value: 给简单数据赋值的
ref: 给对象属性进行赋值的(条件:对象值必须也是有ioc容器管理的)
*****以上二种是用来给属性赋值的
-->
<!--
构造器简单属性赋值方式:
<constructor-arg index="0" value="jack"></constructor-arg>
<constructor-arg index="1" value="18"></constructor-arg>-->
<!--<constructor-arg name="name" value="jack"></constructor-arg>
<constructor-arg name="age" value="18"></constructor-arg>-->
<!--<constructor-arg type="java.lang.String" value="jack"></constructor-arg>
<constructor-arg type="java.lang.Integer" value="18"></constructor-arg>-->
<!--构造器对象属性赋值
ref:指向的是被spring容器管理bean的id
-->
<constructor-arg name="userDao" ref="userDao"></constructor-arg>
2)set方法注入【重点】
public class UserServiceImpl implements UserService {
/*
* spring除了提供了ioc容器用来创建管理对象
* 也提供了一个技术可以用来给对象的各种属性赋值:依赖注入(DI)
* 对象的属性:
* 简单属性:string interger double...
* 对象属性:userDao
* 复杂属性: 数组 list set 单列 | map properties 双列
* 依赖注入(di):构造器方式赋值(了解) set属性方式赋值(掌握--用它)
*
* */
/*set方式注入--简单类型*/
private String name;
private Integer age;
public void setName(String name) {
this.name = name;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public void save() {
System.out.println(name+":"+age);
}
/*set方式注入--对象类型*/
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void save() {
userDao.save();
}
/*set方式注入--复杂单列类型*/
private Set<Object> arr;
public void setArr(Set<Object> arr) {
this.arr = arr;
}
@Override
public void save() {
System.out.println(arr);
}
/*set方式注入--复杂双列类型*/
private Properties properties;
public void setProperties(Properties properties) {
this.properties = properties;
}
@Override
public void save() {
System.out.println(properties);
}
/*set方式注入--复杂双列类型*/
private Map<String,Object> map;
public void setMap(Map<String, Object> map) {
this.map = map;
}
@Override
public void save() {
System.out.println(map);
}
}
<!-- dao -->
<bean id="userDao" class="cn.itcast.daoimpl.UserDaoImpl"></bean>
<!--service -->
<bean id="userService" class="cn.itcast.serviceimpl.UserServiceImpl">
<!--set属性注入方式
property
name属性:按照set后面的值来定位属性的(首字母小写)
value属性:给简单类型赋值
ref属性:给对象属性进行赋值的(条件:对象值必须也是有ioc容器管理的)
-->
<!--简单属性-->
<property name="name" value="jack"></property>
<property name="age" value="18"></property>
<!--对象属性-->
<property name="userDao" ref="userDao"></property>
<!--复杂属性 单列
数组 list set
三组搭配随意用: <array> <list> <set>
-->
<property name="arr">
<set>
<value>abc</value>
<ref bean="userDao"></ref>
</set>
</property>
<!--复杂属性 多列-->
<property name="map">
<map>
<entry key="key1" value="abcd"></entry>
<entry key="key2" value-ref="userDao"></entry>
</map>
</property>
<property name="properties">
<props>
<prop key="username">root</prop>
<prop key="password">root</prop>
</props>
</property>
</bean>
七、Spring注解开发
Spring是轻代码而重配置的框架,配置比较繁重,所以注解开发是一种趋势,注解代替xml配置文件可以简化配置,提高开发效率。
spring的开发方式:
1 全xml方式
特点:所有配置都在xml配置文件中
2 半xml半注解方式
特点:一半使用的是配置文件(第三方) 一半使用的是注解(自己的资源)
3 全注解方式
特点:所有配置全部用注解
spring--全注解(半成品(理解))--springboot(成品 企业开发趋势)--项目一,二
案例:使用spring操作account表做添加(全xml方式 半xml半注解方式 全注解方式)
1.1 spring的半xml和半注解式开发
半xml半注解式:一般我们会将自己的资源用注解代替 第三方资源继续保留XML方式
条件:spring的注解默认是关闭的 需要在xml中配置一个注解扫描器开启注解
开启注解扫描器:<context:component-scan base-package="cn.itcast"></context:component-scan>
注解扫描器的作用:告诉spring去哪些包(包含子包)下解析编写好的注解
使用到的注解概述
ioc:控制反转(将对象交给spring创建管理)
@Component
@Controller
@Service
@Repository
特点:被扫描到后,后将被自己注解的类创建对象 放在ioc容器中
1.需要配置到类上
2.默认不配置标识该对象在spring容器中的唯一标识:就当前类名首字母小写
3.如果配置标识:可以用value指定唯一标识
DI:依赖注入(为spring管理的对象进行属性赋值)
@Autowired
spring默认按照接口类型从容器中查找对象并注入 set属性可以省略不写
@Qualifier
取值 Value:用来指定唯一标识
按照指定的唯一标识从容器中查找对象并注入
特点:没办法单独使用 只能依附@Autowired一起出现
总结:
1 如果ioc中只有一个实现对象,就直接@Autowired
2 如果ioc容器中有多个实现对象,可以使用方式:
@Autowired+@Qualifier(指定id标识) (掌握)
了解:不用
JDK提供的依赖注入的注解
@Resource:按照唯一标识从容器中查找对象并注入
取值 Name:用来指定唯一标识
相当于@Autowired+@Qualifier
生命周期的注解(了解)
@Scope : 对象的作用域 配置在类上
Value属性(singleton| prototype)
@PostConstruct : 配置到方法上 init-method
配置初始化方法
@PreDestory:配置到方法上 destroy-method
配置销毁方法
半xml半注解的执行流程
1.2 spring的全注解式开发(理解)
全注解:自己编写的资源和第三方的资源都用注解方式
ps:该spring的全注解不是最终版 所以很麻烦 等到springboot在该基础做完优化 就是最终版了
条件:
1 使用配置类替换xml配置文件
创建一个类,使用注解申明是一个配置类
2 代码端不在加载配置文件,而是加载配置类
ApplicationContext context=new AnnotationConfigApplicationContext(配置类.class);
使用到的注解
@Configuration:声明配置类 可以省略不写
@ComponentScan: 开启包扫描
取值 basePackages:指定扫描的包
@PropertySource:将properties配置文件交给spring容器管理
取值 value:指定要加载的文件地址
@Bean : 配置到方法上,表明此方法的返回值交给spring容器管理
将第三方对象交给spring容器管理的时候使用@Bean
取值 value:指定在ioc容器中的id标识
@Value:用来取properties中的内容 但是只能设置在成员变量上 类似el表达式获取数据 ${jdbc.username}
@Import(从配置类的.class):引入从配置类
全注解的执行流程图