【Spring】 1. IOC

【Spring】 1. IOC

学习框架前的引言

框架要学什么?

  • 框架的使用
  • 框架的底层原理

框架和类库的区别

  • 类库:就对某个功能的实现,基本上都是一些功能开发的工具。类库相当于挖掘机、推土机、扳手
  • 框架:是对项目整体的架构和设计。框架就相当于建筑物的结构,比如电梯井预留好,只好放入电梯就可以工作了。

框架的难度

  • 完成项目,必须依照框架定义好的规范。如果不符合规范,出现错误很难调试和定位。
  • 新增术语

框架的实现方式

  • 基于xml配置文件的
  • 基于注解的



1. Spring 简介

1.1 Spring 概述

​ Spring是一个开源的设计层面框架,于2003 年兴起的由Rod Johnson创建。Spring是一个分层的JavaSE/EE的一站式、轻量级、开源框架。

  • 一站式:在JavaEE的三层结构中,每一层都提供了不同的解决方案。
  • 轻量级:Spring 是非侵入性的 ,在 IOC 和 AOP 的基础上可以整合各种企业应用的的第三方类库。

1.2 Spring 核心
  • IOC(Inversion of Control):控制反转。降低了业务对象替换的复杂性,提高了组件之间的解耦。

  • AOP(Aspect Oriented Programming):面向切面编程。允许将一些通用任务(如安全、事务、日志等)进行集中式管理,从而实现更好的复用。


1.3 Spring 下载

​ 官网地址:https://spring.io/
​ 类库下载:http://repo.spring.io/release/org/springframework/spring/

1.4 sts

​ sts(spring tool suite):Spring 工具套件。它是一个基于Eclipse的开发环境, 用于开发Spring应用程序。它提供了一个现成的使用环境来实现调试、运行和部署你的Spring应用程序。包括为关键的的服务器和云计算,Git, Maven, AspectJ和最新的Eclipse版本提供整合支持。

​ 各Eclipse版本的sts下载地址 : https://spring.io/tools/sts/legacy。

​ sts 在线安装:使用Eclipse Marketplace ,可直接搜索 sts 安装。



2. IOC

​ IOC(Inversion of Control)中文含义是控制反转。

​ 当需要某个对象实例时,在传统的程序设计过程中,通常由调用者来创建该实例。但在Spring里,创建对象的工作由Spring来完成,因此称为控制反转。IOC 降低了业务对象替换的复杂性,提高了组件之间的解耦。


2.1 原始方式
// Dao层接口
public interface UserDao {	
	void insert();
}
// Dao层实现类
public class UserDaoImpl implements UserDao{
	@Override
	public void insert() {
		System.out.println("插入一条数据...");
	}
}
//原始的方式
UserDao userDao = new UserDaoImpl();
userDao.insert();

​ 原始方式就是手动实例化对象。如果项目中有10处使用 UserDao实例,则需要实例化10次对象。问题在于,当 UserDao的实现方式发生变化时(比如实现类是UserDaoImpl2),这10处位置都需要修改。

​ 换句话说,组件之间的耦合性较高,业务对象替换的比较复杂。


2.2 IOC 底层原理
  • Bean工厂

​ 把组件实例化过程交给工厂,需要实例化对象的时候,调用工厂类的方法统一处理。

public interface BeanFactory {
	//根据id获得bean实例
	Object getBean(String id);	
}
  • 根据全路径类名获得类的实例

    通过反射机制,根据全路径类名,获得类的实例

/**
 * 根据全路径类名获得类的实例
 * 		技术点:反射
 * @param className 全路径类名
 * @return 类的实例
 * @throws Exception
 */
private Object getInstanceByClassName(String className) throws Exception{
	//获得类的加载器
	ClassLoader classLoader = getClass().getClassLoader();
	//加载类
	Class<?> cls = classLoader.loadClass(className);
	//创建实例
	Object obj = cls.newInstance();		
	return obj;
};
  • 配置文件

    在class 类路径下新建配置文件“application-config.xml”,统一对需要实例化的对象进行配置。

<?xml version="1.0" encoding="UTF-8"?>
<!-- beans:根节点,一个xml中只能有一个根节点 -->
<beans>
	<!-- 
		bean:子节点,根节点下可以有多个子节点
			id: 对象实例的别名,后期通过id获得对象实例
			class: 对象类的全路径
	 -->
	<bean id="UserDao" class="com.bodhixu.ssm.UserDaoImpl"/>
</beans>
  • 读取并解析配置文件

    读取配置文件,并通过dom4j进行解析。并通过反射生成实例,放入map集合

/**
 * 读取配置文件,获得bean实例
 * 		技术点:dom4j
 * @param xmlPath 配置文件路径
 * @return bean的map集合
 * @throws DocumentException 
 */
private Map<String, Object> initConfig(String xmlPath) throws Exception {		
	Map<String, Object> beanMap = new HashMap<>();		
	//读取配置文件,获得输入流
	InputStream is = getClass().getResourceAsStream(xmlPath);
	//创建解析器
	SAXReader reader = new SAXReader();
	//加载数据,获得文档模型
	Document doc = reader.read(is);
	//获得文档根节点
	Element rootElement = doc.getRootElement();
	//获得所有bean的子节点
	List<Element> beanElements = rootElement.elements("bean");
	//遍历bean子节点
	for (Element element : beanElements) {
		//获得id属性
		String id = element.attributeValue("id");
		//获得class属性
		String cls = element.attributeValue("class");
		//根据类名获得类的实例
		Object obj = getInstanceByClassName(cls);
		//放入map集合
		beanMap.put(id, obj);
	}		
	return beanMap;
}
  • 根据id获得bean实例

    提供 get 方法,根据 id 返回 bean 对象

public Object getBean(String id) {
  return beanMap.get(id);
}

2.3 BeanFactory 工厂类

在这里插入图片描述

  • BeanFactory:接口

  • ApplicationContext:接口

  • ClassPathXmlApplicationContext:实现类,加载类路径下的配置文件

  • FileSystemXmlApplicationContext:实现类,加载文件系统下的配置文件


2.4 入门程序
  • 导入Spring IOC 所依赖的 jar 包

在这里插入图片描述

  • 在类路径下,创建配置文件“application-config.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">

	<bean id="userDao" class="com.bodhixu.ssm.UserDaoImpl"/>

</beans>
  • 创建 ApplicationContext 对象,通过其获得bean实例。
ApplicationContext context = 
    	new ClassPathXmlApplicationContext("/application-config.xml");
UserDao userDao = (UserDao) context.getBean("UserDao");

2.5 bean 的常用属性
  • id:bean对象的名字,不能包含特殊字符
  • name:和id功能一致,可以包含特殊字符
  • class:bean对象对应类的全路径
  • scope:设置bean的作用域
    • singleton:单例模式,默认的
    • prototype:多例模式
    • request:将实例存入到request域中
    • session:将实例存入到session域中



3. DI

​ DI(Dependency Injection)依赖注入,用来实现对bean对象属性赋值。


3.1 注入方式

​ DI 的实现方式主要有构造器注入和 setter注入,另外其他一些方式如工厂方法注入(很少使用,不推荐)。

  • 构造器注入

必须提供有参构造方法

<bean id="Book" class="com.bodhixu.ssm.demo01.Book">
	<constructor-arg name="name" value="Java"/>
	<constructor-arg name="price" value="200"/>
</bean>
  • setter 注入

    必须提供 setter 方法

<bean id="Book" class="com.bodhixu.ssm.demo02.Book">
	<property name="name" value="Oracle"/>	
	<property name="price" value="200"/>
</bean>

3.2 注入复杂属性
  • 注入 bean 对象
<bean id="book" class="com.bodhixu.ssm.demo03.Book">
	<property name="name" value="Oracle"/>	
	<property name="price" value="200"/>
</bean>

<!-- 注入bean -->
<bean id="student" class="com.bodhixu.ssm.demo03.Student">
	<property name="name" value="小张"/>
	<property name="book" ref="book" />
</bean>
  • 注入数组、集合
<?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="book1" class="com.bodhixu.ssm.demo04.Book">
		<property name="name" value="java"/>
		<property name="price" value="100"/>
	</bean>
	
	<bean id="book2" class="com.bodhixu.ssm.demo04.Book">
		<property name="name" value="orcle"/>
		<property name="price" value="200"/>
	</bean>
	
	<!-- 注入数组、集合 -->
	<bean id="Student" class="com.bodhixu.ssm.demo04.Student">
	
		<!-- 注入数组 -->
		<property name="arr">
			<array>
				<value>arrItem1</value>
				<value>arrItem2</value>
			</array>
		</property>		
		
		<!-- 注入List -->
		<property name="list">
			<list>
				<value>listItem1</value>
				<value>listItem2</value>
			</list>
		</property>
		
		<!-- 注入Set -->
		<property name="set">
			<set>
				<value>listItem1</value>
				<value>listItem2</value>
			</set>
		</property>
		
		<!-- 注入Map -->
		<property name="map">
			<map>
				<entry key="mapkey1" value="mapValue1" />
				<entry key="mapkey2" value="mapValue2" />
			</map>
		</property>
	
				
		<!-- 注入Bean的List -->
		<property name="books">
			<list>
				<ref bean="book1"/>
				<ref bean="book2"/>
			</list>
		</property>
	</bean>
	
</beans>

3.3 命名空间注入

​ 为了简化XML文件的属性配置,Spring从2.5后,引入了新的p命 名空间。

  • 声明p命名空间,可以通过 sts 实现

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0AmksVvj-1587633631341)(img/img7.png)]

xmlns:p="http://www.springframework.org/schema/p"
  • 采用 p 命名空间注入属性值
<bean id="Book" class="com.bodhixu.ssm.demo05.Book"
		p:name="HTML" p:price="60"/>
  • Spring从3.0后,引入了新的c命 名空间。

3.4 SpEL 注入

​ SpEL(Spring Expression Language)Spring的表达式语言。
​ 语法:#{SpEL}

<bean id="book1" class="com.bodhixu.ssm.demo06.Book">
	<property name="name" value="Oracle"/>	
	<property name="price" value="200"/>
</bean>

<!-- spEL注入 -->
<bean id="book2" class="com.bodhixu.ssm.demo06.Book">
	<property name="name" value="#{'new' + book1.getName()}"/>	
	<property name="price" value="#{200+20}"/>
</bean>



4. 基于注解的Bean管理

​ Spring 中对 Bean 的管理有两种方式,一种是通过 xml 配置来管理,一种是通过注解来管理。

4.1 配置文件
  • 新建配置并引入context约束,可以通过 sts 实现·
<context:component-scan base-package="com.bodhixu.ssm" />
  • 开启注解扫描
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
  
	<!-- 开启注解扫描,扫描指定包 -->
	<context:component-scan base-package="com.bodhixu.web.bean"/>
	
	<!-- 开启注解扫描,扫描多个包(用逗号分隔)-->
	<!-- <context:component-scan base-package="com.bodhixu.web.bean, com.bodhixu.web.dao"/> -->
 	
 	<!-- 只扫描属性上的注解  -->
 	<!-- <context:annotation-config></context:annotation-config>  --> 
 	 
</beans>

4.2 组件注解

组件注解的类型

​ 组件注解注释在类上,共有4个,他们作用一样,只是语义化了。暂时我们使用 @Component 注解,在后面的SrpingMVC 中会使用其他注解。

  • @Component: 组件
  • @Controller : 控制组件(WEB层)
  • @Service :业务组件(业务层)
  • @Repository:仓库组件(持久层)

组件名称的设置

​ 给组件注入名称相当于 xml 配置中的 id 属性,设置名称有3种方式。

  • 通过value属性指定组件名称
@Component(value="book")
public class Book {}
  • 只有一个属性,可以省略value
@Component("book")
public class Book {}
  • 未指定属性名称,默认使用类名小写作为组件名
@Component //名称默认是book
public class Book {}

4.3 作用域注解

​ 使用 @Scope 可以设置Bean的作用域,作用同 xml 中配置 bean 的作用域一样。常用的有 singleton 单例模式和 prototype 多例模式。默认是单例的。

@Scope(value="prototype") //单一属性可以省略value=

4.4 属性注解

​ 使用注解注入属性,对象不需要setter方法。如果有setter方法,注解需要写在setter方法上。

  • @Value:普通属性注入
@Component("book3")
public class Book {
    
	@Value(value="java编程") //单一属性可以省略value=
	private String name;
	@Value("100")
	private int price;
    
}
  • @Resource:使用bean的名字注入
@Component("book4")
public class Book {}

@Component("stu1")
public class Student {
	
	@Resource(name="book4")
	private Book book;

}
  • @Autowired:自动注入bean
@Repository
public class UserDao {
	public void insert() {
		System.out.println("UserDao insert...");
	}	
}

@Service
public class UserService {
	@Autowired
	private UserDao userDao;	
	public void regist() {
		userDao.insert();
	}	
}

class Test {
	@org.junit.jupiter.api.Test
	void test() {
		ApplicationContext context = new ClassPathXmlApplicationContext("/application-config.xml");
		UserService service = (UserService) context.getBean("userService");
		service.regist();		
	}
}


4.5 基于xml和注解管理Bean的区别
  • 注解方式管理,简单快捷,对于自己实现的类,建议使用
  • xml方式管理,相对较繁琐,但对于第三方的类,比如jar包引入的类,需要使用xml方式配置

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值