什么是Spring?
它是一个轻量级,非入侵式的控制反转(IoC)和面向切面(AOP)的容器框架.
Spring是一个生态:可以构建企业级应用程序所需的一切基础设施
通常Spring指的就是Spring Framework,它有两大核心:IOC和AOP
1.IoC和DI的支持
Spring的核心就是一个大的工厂容器,可以维护所有对象的创建和依赖关系,Spring工厂用于生成Bean,并管理Bean,实现高内聚低耦合的设计理念。
通俗的说,通过IOC的方式,如果在一个对象中使用另外的对象,从前我们需要手动地new对象,比如Connection还需要销毁,对象始终会和其他接口或类耦合,而使用IOC,对象的管理与创建都不用我们操心,也可以实现解耦的目的.
IOC(Inversion of control)是什么?
IOC 是一种编程思想,它通过控制反转的方式降低了代码之间的耦合度。在传统的程序设计中,我们通常会直接调用其他对象的方法。但在 IoC 框架中,控制权被反转,对象之间的调用由框架负责管理。这使得代码更易于测试和维护。IOC的目的是DI
DI(Dependency Injection)
DI即依赖注入,DI的前提是IOC,依赖注入的核心思想是将对象的依赖关系从硬编码中解耦出来,使得代码之间的耦合度降低。DI 可以通过构造器注入和Setter方法进行属性注入两种方式实现。
Bean的说明:
- 在Spring框架中,"bean" 是一个被框架实例化、组装和管理的对象。
- Beans可以通过XML配置文件、Java注解或Java配置类配置。
配置bean的方式:
- XML配置文件:通过<bean>标签在XML文件中定义。
- 注解:如@Component, @Service, @Repository, @Controller等。这些注解自动将类注册为Spring应用程序上下文中的bean。
- Java配置:使用@Configuration和@Bean注解在Java类中定义。
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标签:表示配置bean
id属性:表示给bean起名字
class属性:表示给bean定义类型
<bean id="" class=""></bean>
-->
<bean id="userDao" class="com.yaorange.dao.impl.UserDaoImpl"/>
<bean id="userService" class="com.yaorange.service.impl.UserServiceImpl">
<property name="userDao" ref="userDao"></property>
</bean>
</beans>
对应的java类
UserDao接口
public interface UserDao {
void getList();
}
UserDao实现类UserDaoImpl
public class UserDaoImpl implements UserDao {
@Override
public void getList() {
System.out.println("用户列表");
}
}
UserService接口以及实现类代码:
public interface UserService {
void selectUser();
}
public class UserServiceImpl implements UserService {
private UserDao userDao;
@Override
public void selectUser() {
System.out.println("执行service...");
userDao.getList();
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
通过IOC容器获取bean对象
public class Main {
public static void main(String[] args) {
//创建IOC容器
ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
//从IOC容器中获取bean对象
UserService userService = ctx.getBean("userService", UserService.class);
userService.selectUser();
}
}
Bean注解配置案例
@Service
//开启事务管理
@Transactional(rollbackFor = Exception.class)
public class BookServiceImpl implements BookService {
@Autowired
private BooksMapper booksMapper;
@Override
public List<Books> selectAll() {
return booksMapper.selectAll();
}
}
java配置类:
@Configuration
//加载资源路径
@PropertySource("classpath:props/jdbc.properties")
public class JdbcConfig {
@Value("${jdbc.driverClass}")
private String driverClass;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Value("${jdbc.url}")
private String url;
/**配置Druid数据源*/
/**@Bean将返回的dataSource标识为被Spring管理的bean对象*/
@Bean
public DataSource dataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(driverClass);
dataSource.setUsername(username);
dataSource.setPassword(password);
dataSource.setUrl(url);
return dataSource;
}
}
Bean的生命周期:
- 实例化(Instantiation):在这个阶段,Spring容器会根据配置信息或注解来创建Bean的实例。可以通过构造函数实例化,也可以通过工厂方法实例化。
- 属性赋值(Population):在实例化后,Spring容器会将配置的属性值或注解中的属性值注入到Bean实例中。这个过程可以通过setter方法注入,也可以通过字段注入。
- 初始化(Initialization):在属性赋值完成后,Spring容器会调用Bean的初始化方法。在这个阶段,可以进行一些初始化操作,如数据加载、资源准备等。
- 使用(In Use):在初始化完成后,Bean就可以被应用程序使用了。在这个阶段,Bean会被注入到其他Bean中,或者通过Spring容器获取并调用其方法。
- 销毁(Destruction):当应用程序不再需要Bean时,Spring容器会负责销毁Bean。
IOC容器的加载过程:
1.资源定位:
提供bean的配置文件,容器通过BeanDefinitionReader读取配置文件或配置类
2.解析配置文件:
解析描述Bean的定义和依赖关系的配置文件,Bean定义包含了Bean的类名、作用域、构造函数参数、属性值等信息。根据解析的配置信息创建相应的BeanDefinition对象
3.bean的配置和初始化
IOC容器根据解析得到的BeanDefinition对象进行bean配置和初始化;在bean配置的过程中会进行依赖注入;在依赖注入的实现中,会使用反射来动态地创建对象实例
通过资源定位,配置文件解析,容器初始化以及依赖注入这些过程,IOC容器就完成了对象的创建/配置和依赖管理;
IOC容器BeanFactory和ApplicationContext的区别:
- 容器类型与启动时机:BeanFactory是Spring的底层容器,只提供了基本的IoC和DI(依赖注入)功能。当调用getBean方法时,只有在使用到某个Bean时,BeanFactory才会对该Bean进行加载实例化,类似单例模式的懒汉模式。而ApplicationContext作为BeanFactory的子接口,除了提供BeanFactory所具有的功能外,还提供了更完整的框架功能。在启动时,ApplicationContext会预先实例化所有的单例Bean,通过设置bean的属性lazy-init=true来让Bean延迟实例化,类似单例模式的饿汉模式。
- 核心实现:BeanFactory的一个核心实现是XMLBeanFactory,而ApplicationContext的一个核心实现是ClassPathXmlApplicationContext。Web容器的环境我们使用WebApplicationContext并且增加了getServeltContext方法。
实现类:
BeanFactory的实现类:
- XmlBeanFactory:从XML配置文件中加载Bean的定义,并实例化Bean。
- ListableBeanFactory:BeanFactory的子接口,提供了列出所有Bean定义的方法。
- AutowireCapableBeanFactory:自动装配Bean的容器,可以根据Bean的名称、类型或名称模式进行自动装配。
- ConfigurableListableBeanFactory:可配置的ListableBeanFactory,提供了更多的配置选项。
ApplicationContext的实现类
- ClassPathXmlApplicationContext:从类路径下的XML配置文件加载Bean的定义。
- FileSystemXmlApplicationContext:从文件系统中的XML配置文件加载Bean的定义。
- WebApplicationContext:为Web应用程序提供的ApplicationContext实现,可以与Servlet容器集成。
- AnnotationConfigApplicationContext:从Java配置类加载Bean的定义,支持@Configuration和@Bean注解。
- AnnotationBeanNameAutoProxyCreator:自动为带有@Controller或@Repository注解的Bean创建代理。
依赖注入的方式:
setter方式注入
通过类中属性的set方法实现属性赋值
代码示例:
public class UserService {
private UserRepository userRepository;
// 默认的构造函数
public UserService() {
}
// UserRepository的setter方法
public void setUserRepository(UserRepository userRepository) {
this.userRepository = userRepository;
}
public User getUserById(int id) {
return userRepository.findById(id);
}
}
public class UserRepositoryImpl implements UserRepository {
@Override
public User findById(int id) {
// 假设这里是从数据库中查找用户
return new User(id, "Username" + id);
}
}
在xml中通过<property>标签进行setter依赖注入
UserService
类有一个名为setUserRepository
的setter方法,它接受一个UserRepository
类型的参数。在Spring的XML配置文件中,<property>
元素用于指定要注入的属性名称(即setter方法的名称去掉set
前缀)和对应的bean引用。当Spring容器创建UserService
的bean时,它会调用setUserRepository
方法并将userRepository
bean传递给它,从而完成依赖注入。
<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">
<!-- 定义UserRepository的bean -->
<bean id="userRepository" class="com.example.UserRepositoryImpl"/>
<!-- 定义UserService的bean,并通过setter注入UserRepository -->
<bean id="userService" class="com.example.UserService">
<property name="userRepository" ref="userRepository"/>
</bean>
</beans>
构造器方式注入
通过类中构造函数实现属性赋值
代码示例:
public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public User getUserById(int id) {
return userRepository.findById(id);
}
}
xml通过<constructor-arg >标签进行依赖注入
UserService类的依赖项UserRepository
通过XML配置进行了注入。通过使用<constructor-arg>
元素,将UserRepository
类型的bean引用传递给UserService
的构造函数。这样,当Spring容器创建UserService
的实例时,会自动将UserRepository
注入到构造函数中。
<!-- UserService的bean定义 -->
<bean id="userService" class="com.example.UserService">
<constructor-arg ref="userRepository"/>
</bean>
<!-- UserRepository的bean定义 -->
<bean id="userRepository" class="com.example.UserRepository"/>
依赖注入方式选择
- 强制依赖使用构造器进行,使用setter注入有概率不进行注入导致null对象出现
- 可选依赖使用setter注入进行,灵活性强
- Spring框架倡导使用构造器,第三方框架内部大多数采用构造器注入的形式进行数据初始化,相对严谨
- 如果有必要可以两者同时使用,使用构造器注入完成强制依赖的注入,使用setter注入完成可选依赖的注入
- 实际开发过程中还要根据实际情况分析,如果受控对象没有提供setter方法就必须使用构造器注入
- ==自己开发的模块推荐使用setter注入(后期基于注解开发),只有第三方提供的类中没有set方法时才选择构造器注入==
自动装配
自动装配是Spring框架中的一种机制,用于自动将依赖项注入到应用程序对象中。通过自动装配,开发人员可以专注于应用程序的业务逻辑,而不需要手动创建和管理依赖关系。
自动装配的方式:
- byType:根据类型进行自动装配。Spring容器会查找类型与注入点匹配的bean,并将其注入到目标属性或构造函数中。如果找到多个匹配的bean,则会抛出异常。
- byName:根据名称进行自动装配。Spring容器会查找名称与注入点匹配的bean,并将其注入到目标属性或构造函数中。
- constructor:通过构造函数进行自动装配。Spring容器会查找与构造函数参数类型匹配的bean,并将其作为参数传递给构造函数。
- autodetect:自动检测需要注入的bean。Spring容器会根据bean的属性和方法,自动推断需要注入的依赖项,并进行装配。
除了基于XML的配置方式,自动装配还可以通过注解的方式实现。例如,可以使用@Autowired注解来自动注入依赖项。
@AutoWired与@Qualifier的说明
在使用@Autowired注解时,需要注意以下几点:
- @Autowired默认按照类型进行匹配,如果存在多个相同类型的bean实例,会产生歧义。
- 如果需要指定特定的bean实例,可以使用@Qualifier注解。
- @Autowired可以标注在类成员变量、方法及构造函数上,用于标注依赖关系。
- 对于setter注入和构造器注入,可以使用@Autowired注解。
- @Autowired注解会自动创建实体,并自动调用方法中的参数。
@Qualifier,用于解决@Autowired注入时的歧义问题。当Spring容器中有多个相同类型的Bean时,如果没有使用@Qualifier,则Spring会抛出异常,因为无法确定应该注入哪个Bean。使用@Qualifier可以消除这种歧义,让Spring明确注入指定的Bean。
@Qualifier要与@AutoWired一起使用