1. 背景
问题一:什么是spring?
spring是一个轻量级的IOC(控制反转)和AOP(横向切面)容器。
问题二:spring的主要组成?
Spring Core:核心类库,提供IOC服务;
Spring Context:提供框架式的Bean访问方式,以及企业级功能(JNDI、定时任务等);
Spring AOP:AOP服务;
Spring DAO:对JDBC的抽象,简化了数据访问异常的处理;
Spring ORM:对现有的ORM框架的支持;
Spring Web:提供了基本的面向Web的综合特性,例如多方文件上传;
Spring MVC:提供面向Web应用的Model-View-Controller实现。
2. 核心知识点一:IOC
2.1. 原理
IOC通俗地讲就是将使用哪种组件的控制权交到调用方的手中,由调用方来决定使用哪个组件。
这里用代码说明下不采用IOC思想的例子以及使用IOC思想的例子:
2.1.1 一般思路
// 1\. 创建用户功能接口
public interface UserDao {
void getUser();
}
// 2\. 实现接口功能类
public class UserDaoImpl implements UserDao{
@Override
public void getUser() {
System.out.println("获取用户信息");
}
}
// 3\. 创建用户服务接口
public interface UserService {
void getUser();
}
// 4\. 实现接口服务类
public class UserServiceImpl implements UserService{
private UserDao userDao = new UserDaoImpl();
@Override
public void getUser() {
userDao.getUser();
}
}
// 5\. 客户端使用用户服务
public class Test {
public static void main(String[] args) {
UserService userService = new UserServiceImpl();
userService.getUser();
}
}
目前看起来一切代码没有问题,常用的思路也能很好地实现功能需求,现在新的需求来了,要求能够针对用户接口有多种不同的实现类,上面的代码就需要进行以下改进:
// 1\. 新增通过mysql方式获取用户信息
public class UserDaoMysqlImpl implements UserDao{
@Override
public void getUser() {
System.out.println("Mysql获取用户信息");
}
}
// 2\. 新增通过Oracle方式获取用户信息
public class UserDaoOraclImpl implements UserDao{
@Override
public void getUser() {
System.out.println("Oracle获取用户信息");
}
}
// 3\.
public class UserServiceImpl implements UserService{
//private UserDao userDao = new UserDaoMysqlImpl();
private UserDao userDao = new UserDaoOracleImpl();
@Override
public void getUser() {
userDao.getUser();
}
}
尽管客户端的代码不用进行任何改动,但是如果要实现不同的用户功能,就必须改动用户服务类。这就导致了一个非常严重的后果,在具体的业务中,一个服务类可能会有多个客户端使用,服务类的改动会导致部分客户端功能失效,因此就应该考虑把选择哪种组件的控制权交到客户端的手中。
2.1.2 IOC思路
将2.1.1的代码进行简单的改造,就能够达到IOC的基本效果。
public class UserServiceImpl implements UserService{
private UserDao userDao;
public void setUserDao(UserDao userDao){
this.userDao = userDao;
}
@Override
public void getUser() {
userDao.getUser();
}
}
//客户端使用代码
public class IocTest {
public static void main(String[] args) {
UserServiceImpl userService = new UserServiceImpl();
userService.setUserDao(new UserDaoMysqlImpl()); //可以根据不同的需求改变入参
userService.getUser();
}
}
可以很容易看出,在用户服务类中构建一个set方法,就能够由调用者选择注入哪种类型的组件,从而不必担心新增组件会影响到用户服务类的其他调用者。
2.2 DI(依赖注入)
控制反转IoC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IoC的一种方法
依赖:spring需要托管的对象
注入:将需要托管的对象注入到spring容器
2.3. 装配方式
2.2.1. XML形式
新建一个hello-spring的demo来说明如何通过xml的形式进行依赖注入的相关配置
添加spring相关依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.2.RELEASE</version>
</dependency>
初始化spring配置文件格式
<?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就是java对象 , 由Spring创建和管理-->
<bean id="hello" class="com.luckyuer.pojo.Hello">
<property name="name" value="Spring"/>
</bean>
</beans>
编写相关类
public class Hello {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void show(){
System.out.println("hello: "+name);
}
}
public class BeanTest {
public static void main(String[] args) {
ApplicationContext context= new ClassPathXmlApplicationContext("beans.xml");
Hello hello = context.getBean("hello", Hello.class);
hello.show();
}
}
执行结果:
hello: Spring</pre>
通过上面的例子可以回答关于控制反转的几个问题:
Hello对象是由谁创建的?--spring容器
Hello对象的属性值是由谁设置的? --spring容器
现在能否将上面用户案例进行改造,使之采用spring的依赖注入功能?答案当时是肯定的。
<?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就是java对象 , 由Spring创建和管理-->
<bean id="userDaoImpl" class="com.luckyuer.dao.UserDaoImpl"></bean>
<bean id="userDaoMysqlImpl" class="com.luckyuer.dao.UserDaoMysqlImpl"></bean>
<bean id="userServiceImpl" class="com.luckyuer.service.UserServiceImpl">
<property name="userDao" ref="userDaoImpl"/>
</bean>
</beans>
public class BeanTest {
public static void main(String[] args) {
ApplicationContext context= new ClassPathXmlApplicationContext("beans.xml");
UserServiceImpl userService = context.getBean("userServiceImpl", UserServiceImpl.class);
userService.getUser();
}
}
通过上面的测试我们可以看到,通过spring可以实现,无需更改任何代码,只需要进行xml文件的配置,就可以实现不同的操作。所谓IOC,就是对象由spring来创建、管理及装配。
拓展:
由spring容器管理的bean在容器初始化的时候已经创建好对象
spring容器中的对象默认是单例的,但是可以通过scope参数进行设置。
2.2.2. 注解形式
核心注解:@Autowired
使用之前, 需要在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
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!--开启注解-->
<context:annotation-config/>
</beans>
2.2.3 JAVA Config形式
核心注解:@bean @ComponentScan @Component
使用这种方式,将完全脱离xml文件的限制,使用java代码就可以完成spring装配bean的工作。
<!--bean扫描-->
<context:component-scan base-package="com.luckyuer.bean" />
@Component
public class Apple {
private String name;
private int age;
}
可以通过IDE的spring管理工具查看容器中bean