目录
1、理解loC是什么
2、基于XML实现Spring的IOC(这种方式已经不怎么使用了)
3、基于注解实现Spring的IOC
4、基于javaConfig实现Spring的IOC
5、总结
1、理解loC是什么
lOC:lnversion of Control 控制反转,简称就是 IOC
控制反转:控制(对象创建权利)被反转
控制反转通过依赖注入(DI)方式实现对象之间的松耦合关系。程序运行时,依赖对象由辅助程序动态生成并注入到被依赖对象中,动态绑定两者的使用关系。Spring IoC 容器就是这样的辅助程序,它负责对象的生成和依赖的注入,然后再交由我们使用。
依赖注入(DI)Dependency Injection,它是 spring 框架核心 ioc 的具体实现。其作用是去除Java类之间的依赖关系,实现松耦合,以便于开发测试。
假设我现在有两个java类,UserService 和 UserDao,然后 UserService 中有依赖 UserDao,这时候创建 UserService 有如下两种情况:
用IOC之前:由程序员控制创建对象
自己创建对象:UserService(new UserDao())---->UserDao;这种方式具有强耦合,再小的代码变更都会引起BUG的可能性
比如在UserService类中要用到UserDao类,就需要在UserService类中创建UserDao类的对象,这就会造成类之间的强耦合。写代码的耦合度越高,对后期的维护就越不利,比如说以后要把UserDao类给换掉的话,就必须来到UserService类中把UserDao类的对象代码给换掉,如果有几十处,就要改几十处,但是再小的代码变更都会引起BUG的可能性
用IOC之后:创建对象依赖Spring注入(DI)
Spring(new UserService(); new UserDao();) 由Spring来创建UserService类和UserDao类的对象,如果UserService中要用到UserDao就让Spring把UserDao注入进来
如果需要用到Spring管理的对象,需要依赖Spring注入(DI)
loC/DI优点:解耦,管理好对象的创建和依赖,总的来说就是统一管理对象。某一个对象只会创建一次,可以节省内存的开支,这属于设计模式当中的一种,设计模式有23种,这种属于单例设计模式,Sprig的管理对象就用到了这个单例设计模式,但是我们自己也可以把他改成每一次用到都给他创建一次
没有引入Spring降低耦合度的方式:
这种方式就是,创建一个接口,通过把将来可能要换的类去实现这个接口,使用时都是用这个接口的实现类,当需要把这个实现类换掉的时候,就只需要再创建这个接口的实现类,然后把之前的那个实现类换成这个新创建的实现类就可以了
示例:
//定义接口
public interface IUserDao {
//执行查询用户
void getUser();
}
//实现IUserDao接口的类,这个类在UserService中需要用到
public class UserDao implements IUserDao{
@Override
//执行查询用户
public void getUser() {
System.out.println("Holle Spring");
}
}
//UserService中需要用到UserDao,但是要降低和UserDao之间的耦合度
public class UserService {
//用IUserDao来接收UserDao的实现类
//这样当以后要把UserDao换成其他实现了IUserDao的类
//就只需要把实现类(也就是现在UserDao的位置)改成要换的那个IUserDao实现类就可以了
IUserDao userDao = new UserDao();
//比如要换成User2Dao,只需要改成:IUserDao userDao = new User2Dao();就可以了
public void getUser() {
userDao.getUser();
}
}
这种方式确实能够降低耦合度,但还是需要修改代码,而通过Spring的loC/Dl就可以实现不需要修改代码来降低耦合度
bean:在 Spring 中,构成应用程序主干并由 Spring IoC 容器管理的对象称为 bean。bean 是由Spring IoC 容器实例化、组装和管理的对象。
2、基于XML实现Spring的IOC(这种方式已经不怎么使用了)
通过在 xml 文件中用 <bean class=""> 这个标签的方式来进行显式的声明要配置成bean的类,生成 applicationContext.xml 文件步骤,但是要在pom.xml文件中引入spring-context依赖才会出现生成 applicationContext.xml 文件这一选项
bean 标签:在 Spring 的 XML 配置文件中配置一个 bean 标签,该标签最终会被加载为一个 BeanDefition 对象(描述对象信息),这个标签里面就用来描述要配置成bean的那个类的信息,这个标签里面像 ref、name 这些属性如果感兴趣的话可以去查阅一下,因为这种方式不怎么用了,所以这里就演示一下大概的流程
//pom.xml文件中需要引入的依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.1.2</version>
</dependency>
//applicationContext.xml 文件配置
//在我的项目中,我把applicationContext.xml文件命名为spring.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">
<!--让Spring帮我们去new对象,对象之间的依赖也让spring帮我们进行组织-->
<bean class="com.lt.service.UserService">
<!--进行注入-->
<property name="userDao" ref="userDao"></property>
</bean>
<bean class="com.lt.dao.UserDao" name="userDao"></bean>
<bean class="com.lt.dao.User2Dao" name="user2Dao"></bean>
</beans>
//创建接口IUserDao
public interface IUserDao {
//执行查询用户
void getUser();
}
//接口IUserDao的实现类UserDao
public class UserDao implements IUserDao{
@Override
//执行查询用户
public void getUser() {
System.out.println("Holle Spring");
}
}
//接口IUserDao的实现类User2Dao
public class User2Dao implements IUserDao{
@Override
//执行查询用户
public void getUser() {
System.out.println("Holle Spring 222");
}
}
//创建接口IUserService
public interface IUserService {
void getUser();
}
//接口IUserService的实现类UserService
//因为这种方式是基于get和set属性来进行注入的,所以要把UserService类的get和set方法声明一下
public class UserService implements IUserService{
//耦合度过高 依赖spring注入(DI)
IUserDao userDao;
public IUserDao getUserDao() {
return userDao;
}
public void setUserDao(IUserDao userDao) {
this.userDao = userDao;
}
@Override
public void getUser() {
userDao.getUser();
}
}
//测试类
public class Test01 {
@Test
public void test(){
//UserService userService = new UserService();
//如果是自己new一个UserService,Spring是不会为这个自己new的UserService注入userDao的
//要依赖spring注入,就需要从spring容器中获取UserService
ClassPathXmlApplicationContext ico = new ClassPathXmlApplicationContext("spring.xml");
IUserService service = ico.getBean(IUserService.class);
service.getUser();
}
}
注入UserDao时的运行结果
注入User2Dao时的运行结果
3、基于注解实现Spring的IOC
通过 @component注解也可以将一个类声明为 Bean通过这种方式就不需要再在applicationContext.xml文件来进行复杂的添加每一个需要被配置成bean的类了
//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"
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 https://www.springframework.org/schema/context/spring-context.xsd">
<!--告诉spring注解所在的包在哪,在com.lt包下面的包-->
<context:component-scan base-package="com.lt"></context:component-scan>
</beans>
//IUserDao是一个接口
public interface IUserDao {
//执行查询用户
void getUser();
}
@Component //标识当前类交给spring去new(实例化),交给spring进行管理,spring组件-bean
public class UserDao implements IUserDao{
@Override
//执行查询用户
public void getUser() {
System.out.println("Holle Spring");
}
}
//@Component //标识当前类交给spring去new(实例化),交给spring进行管理,spring组件-bean
public class User2Dao implements IUserDao{
@Override
//执行查询用户
public void getUser() {
System.out.println("Holle Spring 222");
}
}
public interface IUserService {
void getUser();
}
@Component
public class UserService implements IUserService{
@Autowired //让spring自动注入进来
IUserDao userDao;
@Override
public void getUser() {
userDao.getUser();
}
}
public class Test01 {
@Test
public void test(){
//UserService userService = new UserService();
//如果是自己new一个UserService,Spring是不会为这个自己new的UserService注入userDao的
//要依赖spring注入,就需要从spring容器中获取UserService
ClassPathXmlApplicationContext ico = new ClassPathXmlApplicationContext("spring.xml");
IUserService service = ico.getBean(IUserService.class);
service.getUser();
}
}
想要注入哪一个类就在那一个类上添加@Component注解
运行结果
运行结果
4、基于javaConfig实现Spring的IOC
通过javaConfig(配置类)这种方式就不需要再在applicationContext.xml文件来配置要扫描的包是哪一个了,我们可以新建一个java类(javaConfig类)来代替这个xml文件,创建这个JavaConfig类,这里我把命名为SpringCopnfig,放在config文件下
ClassPathXmlApplicationContext 是基于xml配置的容器,这种方式不用xml文件了,所以用来获取对象的Spring容器也需要更改,这里需要用 AnnotationConfigApplicationContext 这个容器
然后就运行test02这个方法
相关代码:除了javaconfig(配置类)和测试方法的代码,其他代码没改动,和上面基于注解实现Spring的IOC中的代码一样
/*这个配置类就用来代替xml*/
@Configuration // = xml的配置文件
@ComponentScan("com.lt") //这个注解告诉spring要扫描的包在哪里,等于在xml文件中配置的 <context:component-scan 标签
public class SpringConfig {
}
public class Test01 {
@Test //测试基于 XML 实现Spring的IOC的方法
public void test(){
//如果是自己new一个UserService,Spring是不会为这个自己new的UserService注入userDao的
//要依赖spring注入,就需要从spring容器中获取UserService
//(我这里把获得的容器命名为 ioc)
ClassPathXmlApplicationContext ico = new ClassPathXmlApplicationContext("spring.xml");
IUserService service = ico.getBean(IUserService.class);
service.getUser();
}
@Test //测试基于 javaconfig 实现Spring的IOC的方法
public void test02(){
//如果是自己new一个UserService,Spring是不会为这个自己new的UserService注入userDao的
//要依赖spring注入,就需要从spring容器中获取UserService
//从spring容器中获取UserService(我这里把获得的容器命名为 ioc)
AnnotationConfigApplicationContext ico = new AnnotationConfigApplicationContext(SpringConfig.class);
IUserService service = ico.getBean(IUserService.class);
service.getUser();
}
}
5、总结
1.、spring1版本 纯xml文件的方式:这种方式中,如果要把某个类交给Spring帮我们管理,帮我们去 new 这个对象,那就需要把这个类在 xml 文件中配置成相应的 bean,如果要配置的 bean 非常的多的话,那这个 xml 文件的信息就会非常的多,也不利于我们后期的一个维护,开发的效率也非常的低(因为单单去编写这个 xml 文件都要花费许多时间)
2、spring2版本 xml文件 + @(注解)的方式:在这种方式中,我们只需要在 xml 中配置一个扫描包,然后告诉他扫描的包路径,然后他就会通过这个包路径去扫描这个包下面所有的类,一旦发现类里面有个 @component 的注解,那他就会把当前这个类交给 spring 去管理,也就是把当前这个类配置成一个 bean (就是帮我们去 new 这个类的对象)。这中方式下就不需要像 纯xml 的方式那样去编写大量配置 bean 的信息了
3、spring3版本 javaconfig(配置类) + @(注解)的方式:这种方式中,只需要一个 javaconfig(配置类)就可以代替掉之前的 xml 配置文件
【java多线程】通过等待唤醒机制、局部变量、原子变量实现线程同步-CSDN博客https://blog.csdn.net/m0_65277261/article/details/137122461?spm=1001.2014.3001.5501
【java多线程】线程同步问题:用同步代码块、同步方法和重入锁实现线程同步-CSDN博客https://blog.csdn.net/m0_65277261/article/details/137022053?spm=1001.2014.3001.5501【Java多线程】多线程的三种实现方式和多线程常用方法-CSDN博客https://blog.csdn.net/m0_65277261/article/details/136961604?spm=1001.2014.3001.5501