Spring之IoC使用

IOC简介

概念、优点网上一大堆,我只说下自己的见解。所谓控制反转IoC就是在开发过程中,不需要手动的new对象,而是把对象都交给Spring的IOC容器,由Spring容器来创建和注入到需要的相应对象的位置。
不使用SpringIoC的情况下举个例子:在传统的MVC模型中,用户Controller类会调用用户Service类,用户Service类调用用户Dao类,如果实现一个注册功能,需要有以下流程:
Controller需要调用Service中的方法,所以Controller类中必须创建Service对象

public class UserController {

	UserService userService = new UserService();
	
	@Request("/register")
	public void register(User user){
		userService.register(user);
	}
}

Service需要调用Dao层中的方法,所以Service中必须创建Dao对象

public class UserService{
	UserDao userDao = new UserDao();
	
	public void register(User user){
		userDao.insertUser(user);
	}
}

Dao层需要创建数据源,获取数据库连接

public class UserDao{
	DataSource ds = new DataSource(); // 实际上创建数据源还要配置,没这么简单
	public void insertUser(User user){
		ds.getConnection.executeUpdate("INSERT INTO t_user (user_name, password) values (?,?)");
	}
}

上面写了一个MVC开发逻辑层次,有些地方是伪代码,理解即可,可以看到每一层都要new下一层的对象,使用IOC可以避免这种一直new来new去的情况,尤其是在项目中组件很多的时候优势会很明显

使用xml配置IOC

由SpringIoC容器管理对象,那得先告诉容器哪些对象需要放到容器里,哪些对象在哪里会被用到,这些信息都可以保存到配置文件中。(虽然这个方式现在很少用,都是用注解,但是理解配置文件可以深入理解注解方式)
要使用spring ioc首先要引入依赖,maven中引入:

<dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.2.3.RELEASE</version>
</dependency>

配置文件

对于上面的代码,既然不想直接new对象,那么就要靠spring ioc,把这些类的信息告诉spring是通过配置文件实现的,配置文件是一个xml,有固定的格式,我们只要关注其中的bean标签即可。

<?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 id="userService" class="spring.service.UserService">
        <property name="userDao" ref="userDao"></property>
    </bean>
    <bean id="userDao" class="spring.dao.UserDao">
        <property name="mockDataSource" ref="mockDataSource"></property>
    </bean>
    <bean id="mockDataSource" class="spring.dao.MockDataSource"></bean>
</beans>

每个bean就是一个对应的类,bean的id是指当前类在配置文件中的唯一标识,class是类对应的路径,只要一个类就和一个id绑定。
每个bean内的property标签是该类需要被注入的属性,name是该属性的变量名,ref是说明该属性要注入哪个bean。

依赖注入

通过set方法注入

其实只有配置文件还是不够的,配置文件只告诉spring这些类以及类对象要去的地方,但是spring还没有把创建的对象赋值给类属性,赋值过程叫注入。实际上,spring是通过set方法注入的,因此在类中必须写要被注入属性的set方法。比如

public class UserService {

    UserDao userDao;

    public void register(UserEntity user) {
        userDao.insertUser(user);
        System.out.println("Service层执行成功...");
    }

    public void setUserDao(UserDao userDao) {  // spring就是通过这个方法注入的,不写不行!
        this.userDao = userDao;
    }
}
通过构造方法注入

实际上除了通过set方法注入,spring还支持通过构造方法注入!构造方法注入配置文件就要改一下,不能用property了,要用constructor-arg标签,以UserService为例,配置文件改为:

<bean id="userService" class="spring.service.UserService">
        <!--<property name="userDao" ref="userDao"></property>-->
        <constructor-arg name="userDao" ref="userDao"></constructor-arg>
</bean>

UserService改为:

public class UserService {

    UserDao userDao;
    
    public UserService(UserDao userDao) {  // 通过构造方法注入
        this.userDao = userDao;
    }

    public void register(UserEntity user) {
        userDao.insertUser(user);
        System.out.println("Service层执行成功...");
    }
}
bean property 和 constructor-arg其他属性说明

bean标签常用属性
id:bean的唯一标识
name:废弃不建议使用,作用和id差不多
class:bean对应的类的全路径
scope:singleton或prototype,决定了bean的创建时机。
property标签常用属性
name:被注入的属性的变量名
ref:注入bean的id
value:注入基本类型时的值
constructor-arg标签中的属性
name:被注入属性的变量名
ref: 注入的bean的id
value:如果注入的基本数据类型,就直接value而不是ref,注入基本类型时使用
index:指定当前注入对象对应构造方法中第几个参数
type:指定注入的当前值的类型,注入基本类型时使用

第三方包注入

上面的类都是我们自己写的,那么第三方包如何注入呢,比如数据库连接池HikariCP,仔细想一下其实第三方包里面的类也只是个类而已,只要找到它的类路径即可。配置文件如下:

	<bean id="userDao" class="spring.dao.UserDao">
        <property name="mockDataSource" ref="mockDataSource"/>
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <bean id="mockDataSource" class="spring.dao.MockDataSource"/>

    <bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/online_mall"/>
        <property name="username" value="root"/>
        <property name="password" value="12345678"/>
    </bean>

UserDao中通过set方法即可注入DataSource

使用注解配置IOC

xml配置bean的方式在类比较少的时候还好,当类多起来的时候,要不断的扩大配置文件,会比较麻烦,后来就引入了更好的更方便的IOC配置方法,直接使用注解,摒弃冗长复杂的配置文件。

告别配置文件

组件注解和自动装配注解

在类上加上@component 表示这个类是一个spring ioc组件,在spring容器中创建该类的对象
在要被注入的属性上加@AutoWired注解,表示自动注入

@Component
public class UserService {
	@AutoWired
    UserDao userDao;

    public void register(UserEntity user) {
        userDao.insertUser(user);
        System.out.println("Service层执行成功...");
    }
}

@Component
public class UserDao {
	....
}

上述代码就相当于配置文件

	<bean id="userService" class="spring.service.UserService">
        <property name="userDao" ref="userDao"></property>
    </bean>
    <bean id="userDao" class="spring.dao.UserDao"/>
引入第三方包

注解虽好,但是如果一个类在第三方包里怎么办,还是以数据库连接池HikariDP为例,按照注解的套路,我们要在HikariDataSource这个类上加一个@Component,但是这显然是不可能的,因为我们根本无法修改其源码,方法是有的,使用@Configuration和@Bean注解
@Configuration用在类上,注明一个类是Spring配置类
@Bean注解用在方法上,注明该方法返回一个对象,这个对象加入到Spring ioc容器中

@Configuration
public class DataSourceUtils {
    @Bean
    public static DataSource getDataSource() {
        ......
        return new HikariDataSource(config);
    }
}

@Component
public class UserDao {

    @Autowired
    DataSource ds;

    public void insertUser(UserEntity user) {
        ds.executeUpdate(user);
        System.out.println("Dao层执行成功..." + user);
    }
}
其他常用注解

@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)配合@Component使用,注明类的作用域SCOPE_PROTOTYPE是多例, SCOPE_SINGLETON单例

@Component
@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
public class UserService {
	......
}

@PropertySource(“xxx.properties”)用在类上,注明读取配置文件xxx,并在类中使用@Value取值注入配置文件中的内容
配置文件jdbc.properties

# 数据库url
jdbc.url=jdbc:mysql://localhost:3306/online_mall
# 数据库用户名与密码
jdbc.username=root
jdbc.password=12345678
@PropertySource("jdbc.properties")
public class DataSourceUtils {

    @Value("${jdbc.url}")
    private String db_url;
    @Value("${jdbc.username}")
    private String user;
    @Value("${jdbc.password}")
    private String password;

    @Bean
    public DataSource getDataSource() throws SQLException {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl(db_url);
        config.setUsername(user);
        config.setPassword(password);
        return new HikariDataSource(config);
    }
}

@PostConstruct:定义该方法在构造方法之前执行
@PreDestroy:定义该方法在方法结束时执行一次
@Qualifier:配合bean标签定义别名,在注入时配合AutoWired指定注入哪个对象

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值