IOC控制反转一创建对象

简介

IOC(Inversion of controlller),控制反转,是一个思想,概念。把对象的创建,赋值,管理工作都交给代码之外的容器实现,也就是对象的创建是由其他外部资源完成的。

控制:创建对象,对象的属性赋值,对象之间的关系管理

正转:由开发人员在代码中,使用new 构造方法创建对象,开发人员主动管理对象

反转:把原来的开发人员管理,创建对象的权限转移给代码之外的容器实现,由容器代替开发人员管理对象,创建对象。

容器可以是一个服务器软件,一个框架。

IOC可以降低程序之间的耦合,DI(依赖注入)是ioc的技术实现,我们只需要在程序中使用对象名称就可以,至于如何渎职,查找都由内部容器实现。

举例

在Javaweb中我们经常会正在注解中表示servlet类与映射地址之间的关系,其实这里就是将创建对象的权限交给了tomcat服务器。我们并没有在代码中实现new一个对象的实例出来,但是该类却是实实在在的运行了,当然监听器和过滤器也一样。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>AddServlet</servlet-name>
<servlet-class>com.zss.servlets.AddServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>AddServlet</servlet-name>
<url-pattern>/add</url-pattern>
</servlet-mapping>
</web-app>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class AddServlet extends HttpServlet {
@Override
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
//注意要设置编码格式,非常重要,post方式要进行设置
req.setCharacterEncoding("UTF-8");
String fName=req.getParameter("fName");
int price=Integer.parseInt(req.getParameter("price"));
int fCount=Integer.parseInt(req.getParameter("fCount"));
String remark=req.getParameter("remark");
Integer fid=Integer.parseInt(req.getParameter("fid"));


FruitDAOImpl fruitDAO=new FruitDAOImpl();
try {
fruitDAO.addFruit(new Fruit(fName,price,fCount,remark,fid));
} catch (SQLException | ClassNotFoundException e) {
e.printStackTrace();
}

}
}

演示

加入maven依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!-- 1.Spring核心依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.3.19</version>
</dependency>
<!--spring config-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.19</version>
</dependency>

</dependencies>

创建类

1
2
3
public interface testService {
public void doService();
}
1
2
3
4
5
6
public class testServiceImpl  implements testService {
@Override
public void doService() {
System.out.println("执行了service方法");
}
}
1
2
3
4
5
public static void main(String[] args) {
//这里使用了正转的方法,创建类交给我们来进行
testService test=new testServiceImpl();
test.doService();
}

创建xml文件

1
2
3
4
5
6
7
8
9
10
11
12
13
<?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创建对象,id对象自定义名称,class类的全限定名称-->
<bean id="test" class="com.zss.service.impl.testServiceImpl"/>
<!--而spring把创建的文件放入到map中了,实际上执行了springmap.put(id,对象),所以一个bean标签只能声明一个对象-->

</beans>
<!--spring文件的配置文件
beans是跟标签,spring把Java对象称为beans
spring-beans.xsd是约束文件-->

测试

类路径:即我们编译程序之后,在target/classes的路径下面

image-20220503153456871

1
2
3
4
5
6
7
8
9
10
11
public static void main(String[] args) {
//使用spring容器创建对象
//指定spring配置文件名称
String config="beans.xml";
//创建spring容器的对象,applicationcontext---代表spring容器
//ClassPathXmlApplicationContext表示从类路径中加载文件
ApplicationContext applicationContext=new ClassPathXmlApplicationContext(config);
//从容器中根据id获得类的真实类型
testService test=(testService) applicationContext.getBean("test");
test.doService();
}

验证

那么这个spring框架是在那一步将对象创建出来的呢??

我们首先写入无参构造器,如果对象被创建,那么此时构造器会被调用

1
2
3
public testServiceImpl() {
System.out.println("对象被创建了");
}

在debug模式下进行,当我执行完毕ApplicationContext 时,发现无参构造器被调用了,此时对象已经被创建,而下一步只是在map中取出值而已,也就是说在创建spring容器时,所有对象就已经被创建了

image-20220503155311168

当然spring也可以创建一个非自定义对象,同时在创建对象时调用类的无参构造器。

spring获取对象的信息

1
2
3
4
5
6
7
8
//获取容器中定义对象的数量
int nums=applicationContext.getBeanDefinitionCount();
System.out.println(nums);
//获取容器中每一个定义对象的名称
String []names=applicationContext.getBeanDefinitionNames();
for (String name:names){
System.out.println(name);
}

image-20220503160008099