Spring5------------IOC
一、通过配置文件创建类的对象
目录结构

User.java
package com.tang.spring;
public class User {
public void add() {
System.out.println("add");
}
}
bean.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">
<!-- 配置User对象创建-->
<bean id="user" class="com.tang.spring.User"></bean>
</beans>
测试类MyTest.java
package com.tang.spring.testdemo;
import com.tang.spring.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
@Test
public void testAdd() {
//加载spring配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
//获取配置创建的对象
User user = context.getBean("user",User.class);
System.out.println(user);
user.add();
}
}
二、IOC容器
1、IOC底层原理
IOC(Inversion of Control):译为控制反转,把对象创建和对象之间的调用过程,交给Spring进行管理
目的:降低耦合度
IOC底层:工厂设计模式、xml解析、反射
我们可以把IOC容器的工作模式看做是工厂模式的升华,可以把IOC容器看作是一个工厂,这个工厂里要生产的对象都在配置文件中给出定义,然后利用编程语言的的反射编程,根据配置文件中给出的类名生成相应的对象。从实现来看,IOC是把以前在工厂方法里写死的对象生成代码,改变为由配置文件来定义,也就是把工厂和对象生成这两者独立分隔开来,目的就是提高灵活性和可维护性。
2、IOC接口(BeanFactory)
Spring提供IOC容器两种实现方式(两个接口):
BeanFactory:IOC容器基本实现,是Spring内部的使用接口,不推荐开发人员使用这种方式。加载配置文件的时候不会创建对象,使用对象的时候才去创建。
ApplicationContext:BeanFactory接口的子接口,提供更多更强大的功能,一般由开发人员使用。加载配置文件的时候就会将对象进行创建。
ApplicationContext主要实现类:

3、IOC操作:Bean管理
Bean管理指的是两个操作:
- Spring创建对象
- Spring注入属性
Bean管理有两种实现方式:
(1)基于xml配置文件方式实现
bean标签常用属性:
-
- id:bean的唯一标识,不能包含特殊字符
- class:bean类的全路径(包名+类名)
创建对象的时候,默认使用无参构造方法完成对象创建
注入属性的两种方式:
-
- 使用set方法注入属性
- 使用有参构造器注入属性
package com.tang.spring;
public class User {
private String name;
public User() {
}
//使用有参构造器注入属性
public User(String name) {
this.name = name;
}
//使用set方法注入属性
public void setName(String name) {
this.name = name;
}
}
<!--set方法注入属性
Spring会通过反射调用set方法完成注入,故实体类中要写set方法
-->
<bean id="user" class="com.tang.spring.User">
<!--使用property完成属性注入
name:类里面的属性名字
value:向属性注入的值
-->
<property name="name" value="唐三藏"></property>
</bean>
<!--有参构造方法注入属性-->
<bean id="user" class="com.tang.spring.User">
<constructor-arg name="name" value="唐三藏"></constructor-arg>
</bean>
注入外部bean
package com.tang.spring;
public class PrintUser {
private User user01;
public void setUser01(User user01) {
this.user01 = user01;
}
public void print(){
System.out.println(user01);
}
}
<!--有参构造方法注入属性-->
<bean id="user" class="com.tang.spring.User">
<constructor-arg name="name" value="唐三藏"></constructor-arg>
</bean>
<bean id="printUser" class="com.tang.spring.PrintUser">
<!--注入User对象
name:属性名字,必须完全对应(属性名字和set方法名字要有一致性)
ref:注入对象bean标签的id属性值
-->
<property name="user01" ref="user"></property>
</bean>
注入内部bean
package com.tang.spring;
public class Dept {
private String dname;
public String getDname() {
return dname;
}
public void setDname(String dname) {
this.dname = dname;
}
}
package com.tang.spring;
public class Empl {
private String ename;
private String gender;
private Dept dept;
public void setEname(String ename) {
this.ename = ename;
}
public void setGender(String gender) {
this.gender = gender;
}
public void setDept(Dept dept) {
this.dept = dept;
}
public void add(){
System.out.println(ename+"--"+dept);
}
}
<bean id="empl" class="com.tang.spring.Empl">
<!--设置两个普通属性-->
<property name="ename" value="zhangsan"></property>
<property name="gender" value="女"></property>
<!--设置对象类型属性-->
<property name="dept">
<bean id="dept" class="com.tang.spring.Dept">
<property name="dname" value="财务部"></property>
</bean>
</property>
</bean>
注入集合类型
package com.tang.spring;
import java.util.List;
public class Course {
private List<String> cname;
public void setCname(List<String> cname) {
this.cname = cname;
}
}
package com.tang.spring;
import java.util.List;
import java.util.Map;
public class Stu {
private String[] courses;
private List<String> list;
private Map<String,String> map;
private List<Course> courseList;
public void setCourseList(List<Course> courseList) {
this.courseList = courseList;
}
public void setCourses(String[] courses) {
this.courses = courses;
}
public void setList(List<String> list) {
this.list = list;
}
public void setMap(Map<String, String> map) {
this.map = map;
}
}
普通bean:在配置文件中定义的bean类型就是返回类型
工厂bean:在配置文件中定义的bean类型可以和返回类型不一样
创建工厂bean过程:
第一步:创建作为工厂bean的类(实现FactoryBean接口)
第二步:实现接口方法,在实现的方法中定义返回的bean类型
package com.tang.spring;
public class Course {
private String cname;
public void setCname(String cname) {
this.cname = cname;
}
@Override
public String toString() {
return "Course{" +
"cname='" + cname + '\'' +
'}';
}
}
package com.tang.spring;
import org.springframework.beans.factory.FactoryBean;
public class MyBean implements FactoryBean<Course> {
//定义返回bean类型
@Override
public Course getObject() throws Exception {
Course course = new Course();
course.setCname("数据库");
return course;
}
@Override
public Class<?> getObjectType() {
return null;
}
@Override
public boolean isSingleton() {
return false;
}
}
在Spring里面,默认情况下,bean是单实例对象
scope属性值:
- singleton(默认),表示是单实例对象,加载spring配置文件的时候就会创建单实例对象
- prototype,表示是多实例对象,在调用getBean方法的时候创建多实例对象
自动装配(不常用)
bean标签属性autowire,配置自动装配
autowire属性值:
- byName:根据属性名称注入
- byType:根据属性类型注入
外部属性文件
直接配置连接池
<!-- 直接配置连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/munumanage"></property>
<property name="username" value="root"></property>
<property name="password" value="admin"></property>
</bean>
引入外部属性文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 引入外部属性文件-->
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<!-- 配置连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${mydata.driverClassName}"></property>
<property name="url" value="${mydata.url}"></property>
<property name="username" value="${mydata.username}"></property>
<property name="password" value="${mydata.password}"></property>
</bean>
</beans>
jdbc.properties
mydata.driverClassName=com.mysql.cj.jdbc.Driver mydata.url=jdbc:mysql://localhost:3306/munumanage mydata.username=root mydata.password=admin
(2)基于注解方式实现
使用注解目的:简化xml配置
Spring针对Bean管理中创建对象提供的注解:
- @Component
- @Service
- @Controller
- @Repository
上面四个注解功能是一样的,都可以用来创建bean实例
Spring针对Bean管理中属性注入提供的注解:
- @Autowired:根据属性类型进行注入(byType)
- @Qualifier:根据属性名称进行注入(byName)
- @Resource:既可以根据属性类型注入,也可以根据属性名称注入
- @Value:注入普通类型属性
注意:前三个是注入对象类型属性;使用@Qualifier注解,必须和@Autowired配套使用,不然会导致bean注入失败
第一步:引入依赖

第二步:开启组件扫描
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 开启组件扫描
如果要扫描多个包,包之间用逗号隔开
-->
<context:component-scan base-package="com.tang.spring"></context:component-scan>
</beans>
<!-- 细节
use-default-filters 表示不使用默认filter,自己配置filter
context:include-filter 设置扫描哪些内容
type="annotation" expression="org.springframework.stereotype.Component" 表示扫描@Component注解
-->
<context:component-scan base-package="com.tang.spring" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/>
</context:component-scan>
<!-- 细节
使用默认filter
context:exclude-filter 设置哪些内容不进行扫描
-->
<context:component-scan base-package="com.tang.spring">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Component"/>
</context:component-scan>
第三步:创建类,在类上面添加创建对象注解
package com.tang.spring;
import org.springframework.stereotype.Component;
//value属性可以省略不写,默认值为类名,首字母小写
@Component(value = "user") // 和<bean id="user" class="com.tang.spring.User"></bean>作用一样
public class User {
private String name;
public User() {
}
public User(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
}
第四步:属性注入
package com.tang.spring;
public interface UserDao {
public void print();
}
package com.tang.spring;
import org.springframework.stereotype.Repository;
@Repository(value = "userDaoImplOne")
public class UserDaoImpl implements UserDao{
@Override
public void print() {
System.out.println("UserDaoImpl print");
}
}
package com.tang.spring;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
public class UserService {
//不需要添加set方法
//@Resource 根据类型进行注入
//@Resource(name = "userDaoImplOne") 根据名称进行注入
@Autowired //根据属性类型进行注入
@Qualifier(value = "userDaoImplOne")
private UserDao userDao;
@Value(value = "zhangsan")
private String name;
public void print(){
System.out.println("UserService print");
userDao.print();
}
}
完全注解开发
配置类替代xml
package com.tang.spring;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Controller;
@Controller //指定当前类作为配置类,替代xml文件
@ComponentScan(basePackages = {"com.tang.spring"})
public class MyConfig {
}
测试类
package com.tang.spring.testdemo;
import com.tang.spring.*;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
@Test
public void testAdd() {
//加载配置类
ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
//获取配置创建的对象
UserService userService = context.getBean("userService", UserService.class);
userService.print();
}
}
浙公网安备 33010602011771号