浅谈下Spring IoC和DI以及 Spring 实操
一、Spring
1. 为什么要使用Spring?
-
解决代码耦合度高的问题
以前的代码都是类似private IEmployeeDAO employeeDAO = new EmployeeDAOImpl();这样的代码,对象都是我们手动创建的,假如将实现类改成其它的,那就需要修改涉及到这个实现类的代码,这样大大增加了维护成本。(不符合开放-封闭原则)
-
解决控制事务繁琐问题
如果需要对某些业务方法进行事务管理,则需要写上开启事务、保存业务、提交事务、回滚事务等代码,假如有很多个业务方法都需要进行事务管理,则会造成大量重复代码,同时,维护上也很不方便。
-
解决第三方框架运用太麻烦
单纯使用MyBatis框架,则需要进行获取session对象、获取Mapper对象、执行相应SQL语句、提交事务、释放资源等,而对于使用者只关心使用的问题,而不在乎创建的问题。就比如我们需要使用手机打电话,我们关心的是直接使用手机,而不是自己造一部手机出来。
2. Spring是什么?
- Spring是一种轻量级的 IoC、DI 和 AOP 容器的开源框架。
- 简单地说,Spring可以帮我们创建以及管理配置好的对象,设置对象的属性值,并将对象(单例)存到Spring容器中,而我们需要用的时候,直接从Spring容器取出来就可以使用。
3. Spring的优势
Spring 除了不能帮我们写业务逻辑,其余的几乎什么都能帮助我们简化开发,作用如下
- Spring 能帮我们低侵入/低耦合地根据配置文件创建及组装对象之间的依赖关系。
- Spring 面向切面编程能帮助我们无耦合的实现日志记录,性能统计,安全控制等。
- Spring 能非常简单的且强大的声明式事务管理。
- Spring 提供了与第三方数据访问框架(如Hibernate、JPA)无缝集成,且自己也提供了一套 JDBC 模板来方便数据库访问。
- Spring 提供与第三方 Web(如 Struts1/2、JSF)框架无缝集成,且自己也提供了一套 Spring MVC 框架,来方便 Web 层搭建。
- Spring 能方便的与如 Java Mail、任务调度、缓存框架等技术整合,降低开发难度。
4. Spring FrameWork体系
5. Spring依赖
<!-- spring上下文依赖 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.8.RELEASE</version> </dependency> <!-- spring测试依赖 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.0.8.RELEASE</version> <scope>test</scope> </dependency>
二、IoC 和 DI
1. IoC
- Inversion of Control,控制反转
- 将在程序中手动创建对象的控制权交给 IoC 容器,由 IoC 容器进行创建对象和管理对象
2. DI
- Dependency Injection,依赖注入
- 创建对象过程中,将对象依赖属性(常量、对象)通过配置设置值给该对象
IoC 和 DI都是一种思想或者称为想法,而Spring是这两种思想实现之一
三、Spring 基础知识
1. BeanFactory和ApplicationContext
2. Spring 配置方式
- XML-based configuration
- Annotation-based configuration
- Java-based configuration
3. Spring IoC 管理 Bean 的原理
- 通过Resource对象加载配置文件
- 解析配置文件和Bean元素,将id作为bean的名字,class通过反射创建bean的实例
bean类必须存在一个无参构造器 - 调用getBean()方法时,从容器中返回对象实例
4. XML基本配置
<context:property-placeholder location="classpath:db.properties"/> <!-- 若类名字以 FactoryBean 结尾,需要注意具体创建什么类型的对象存到容器中 初始化和销毁方法目前只有数据源对象才会配置 --> <bean id="唯一性" class="类全限定名" [init-method="初始化方法名" destroy-method="销毁方法名"]> <property name="属性名" value="属性值"|ref="容器中另外一个 bean 的 id 值"/> ...... </bean> ......
5. 实现 FactoryBean 接口实例化
Spring在对整个bean元素解析创建对象时,会先创建该工厂对象,但检测到这个类实现了FactoryBean接口,则会使用工厂对象调用getObject()方法创建bean对象,并把bean对象存入容器中。
集成 MyBatis 框架使用,就会配置 org.mybatis.spring.SqlSessionFactoryBean
6. Bean
-
bean的创建时机:启动 Spring 容器的时候创建所有的 bean
-
作用域:singleton(默认)、prototype、request、session、application
-
初始化和销毁:在配置文件中设置
-
正常关闭容器,才会执行销毁方法
-
bean的scope为prototype时,容器只负责创建和初始化,不负责销毁。
因为多例对象是一次性的,不需要进行保存,存放在spring容器外,如果存放在spring容器内,那么就会导致容器被这些对象占满
-
四、第一个 Spring 程序
-
新建 Maven 项目并设置编译版本及添加依赖(pom.xml)
<properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>16</maven.compiler.source> <maven.compiler.target>16</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.9</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.45</version> <scope>runtime</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.20</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.8.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.0.8.RELEASE</version> <scope>test</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> </dependencies>
-
创建表
CREATE TABLE `employee` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `username` varchar(255) DEFAULT NULL, `password` varchar(255) DEFAULT NULL, `age` int(11) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
编写数据库四要素(db.properties)
jdbc.driverClassName=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql:///spring-demo jdbc.username=root jdbc.password=admin
-
编写 DAO 层代码
public interface IEmployeeDAO { void save(String username, String password, age) throws Exception; }
public class EmployeeDAOImpl implements IEmployeeDAO { private DataSource dataSource; public void setDataSource(DataSource dataSource) { this.dataSource = dataSource; } @Override public void save(String username, String password, age) throws Exception { @Cleanup Connection connection = dataSource.getConnection(); @Cleanup PreparedStatement ps = connection.prepareStatement("INSERT INTO employee(username, password, age) VALUES(?, ?, ?)"); ps.setString(1, username); ps.setString(2, password); ps.setInteger(3, age); ps.executeUpdate(); } }
-
编写业务层代码
public interface IEmployeeService { void save(String username, String password, Integer age) throws Exception; }
public class EmployeeServiceImpl implements IEmployeeService { private IEmployeeDAO employeeDAO; public void setemployeeDAO(IEmployeeDAO employeeDAO) { this.employeeDAO = employeeDAO; } @Override public void save(String username, String password, age) throws Exception { employeeDAO.save(username, password, age); } }
-
编写 Spring 配置文件(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 http://www.springframework.org/schema/context/spring-context.xsd"> <context:property-placeholder location="classpath:db.properties"/> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> <property name="driverClassName" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <bean id="employeeDAO" class="cn.regex.ims.dao.impl.EmployeeDAOImpl"> <property name="dataSource" ref="dataSource"/> </bean> <bean id="employeeService" class="cn.regex.ims.service.impl.EmployeeServiceImpl"> <property name="employeeDAO" ref="employeeDAO"/> </bean> </beans>
-
编写测试类(EmployeeServiceTest.java)
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class EmployeeServiceTest { @Autowired private IEmployeeService employeeService; @Test public void save() throws Exception { Employee employee = new Employee(); employee.setUsername("regex"); employee.setPassword("123456"); employee.setAge(15); employeeService.save(employee); } }