前言
前一段时间简单学习了Spring,了解核心内容IoC和AOP,根据学习的东西简单总结记录下。
参考链接
Spring概念:https://baike.baidu.com/item/spring%E6%A1%86%E6%9E%B6/2853288?fr=aladdin
知识点
一. 基础概念
1.1 spring:分层的JavaSE/EE应用full-stack轻量级开源框架,以IoC(Inverse Of Control反转控制)和AOP(Aspect Oriented Programmin 面向切面编程)为内核,提供表示层SpringMVC/持久层Spring JDBC/业务层等应用技术,整合开发第三方框架和类库,逐渐成为使用最多的Java EE企业应用开源框架。
1.2 spring的优势:
- 方便解耦,简化开发:通过Spring提供的IoC容器,可将对象间的依赖关系交由Spring进行控制,避免硬编码所造成的程序过度耦合。用户也不必再为单例模式类/属性文件解析等底层需求编写代码,可更专注于上层应用
- 支持AOP编程:符合开闭原则(对扩展开放,对修改关闭),使用AOP(核心原理是反向代理)增强功能;在OOP(面向对象编程,继承携带的纵向开发)基础上添加横向编程的功能。实现用统一的代码给项目中的大多数地方增强统一功能。
- 支持声明式事务:可通过声明式方式进行事务,提高开发效率和质量(使用@Transactional注解实现事务注入,保证数据库多操作的安全性和原子性)
- 方便程序测试:可用非容器依赖的编程方式进行几乎所有的测试工作
- 方便集成各种优秀框架:Spring可以降低各种框架的使用难度,提供对各种优秀框架(Struts/Hibernate/Quartz)的直接支持
- 降低JavaEE API的使用难度:Spring对JavaEE API(如JDBC/JavaMail/远程调用等)进行封装,使其使用难度大大降低
- Java源码学习范例:Spring源代码设计精妙/结构清晰,源代码是Java技术的最佳实践的范例
1.3 Spring体系结构
二. IoC
2.1 程序耦合性分析
耦合:即程序间的依赖关系。包括类之间的依赖和方法间的依赖。需要明确的一点是程序间的依赖关系是无法完全取消的,我们能做的就是尽可能的降低程序间的依赖程度
解耦:降低程序间的依赖关系
对于程序间依赖关系的理解:一般程序间调用多使用new对象,这种方法无形中增强了程序间的互相调用依赖关系,并且这种依赖是编译程序的时候获得的(一个Java程序需要经过先编译成字节码文件即.class,然后在JVM环境中运行字节码文件);并且有一个认知就是其实程序可以到运行期再互相调用,这样的话我们可以在实际开发中做到编译期不依赖,运行时才依赖。
解耦的实现思路:利用反射+声明要依赖对象的全限定类名(可基于xml 的配置文件;可基于注解)
举例:传统的MVC工程。分为dao-service-test测试
//AccountDao持久化层接口
public interface AccountDao {
/**
* 模拟保存用户
*/
void saveAccount();
}
//AccountDaoImpl持久化实现类
public class AccountDaoImpl implements AccountDao {
public void saveAccount() {
System.out.println("save account");
}
}
//AccountService业务层接口
public interface AccountService {
/**
* 模拟保存Account账户
*/
void saveAccount();
}
//AccountServiceImpl业务层实现类
public class AccountServiceImpl implements AccountService {
private AccountDao accountDao = new AccountDaoImpl();
public void saveAccount() {
accountDao.saveAccount();
}
}
//测试类
public class Client {
public static void main(String[] args) {
AccountService accountService = new AccountServiceImpl();
accountService.saveAccount();
}
}
存在的问题:通过new方法获取service和dao对象,程序中类间的依赖性很强,如果一个类没有的话,编译时会直接报错
2.2 使用工厂模式降低程序耦合性
2.2.1 创建实体类全限定类名配置的配置文件(可xml;可properties)
#配置类全限定名key=value,value为全限定类名(在项目中的路径.实现类名)
accountService=com.practice.spring.service.impl.AccountServiceImpl
accountDao=com.practice.spring.dao.impl.AccountDaoImpl
2.2.2 创建Bean对象的工厂类,读取配置文件并根据反射创建对象
public class BeanFactory {
//定义一个Properties对象
private static Properties properties;
//使用静态代码块为Properties对象赋值
static {
try{
//实例化对象
properties = new Properties();
//获取properties文件的流对象 //推荐使用反射(类名.class)+类加载器动态加载配置文件
properties.load(BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties"));
}catch (Exception e){
throw new ExceptionInInitializerError("初始化Properties失败");
}
}
/**
* 根据bean的名称获取bean对象
* @param beanName
* @return
*/
public static Object getBean(String beanName){
Object bean = null;
try{
String beanPath = properties.getProperty(beanName);
//利用反射Class.forName(classPath)创建bean对象
bean = Class.forName(beanPath).newInstance(); //每次都会调用默认构造函数创建对象
}catch (Exception e){
e.printStackTrace();
}
return bean;
}
}
2.2.3 工厂模式创建对象
主要体现在AccountServiceImpl对AccountDao对象的创建以及测试类中对AccountService对象的创建。
//AccountServiceImpl业务层实现类
public class AccountServiceImpl implements IAccountService {
// private AccountDao accountDao = new AccountDaoImpl(); //不再通过new来创建对象
private AccountDao accountDao = (AccountDao) BeanFactory.getBean("accountDao"); //而是通过工厂类的getBean方法,通过key获取配置文件中的全限定类名;
//通过反射加载类,然后通过newInstance()创建AccountDaoImpl对象(编译器运行的时候才会通过反射创建这个对象)
//注意创建对象返回的是Object类型,需要进行类型强制转换(父类 对象名 = new 子类(),变量可以复用子类的所有,方法之只能用父类的,方法看右变量看左)
public void saveAccount() {
accountDao.saveAccount();
}
}
//test测试类
public class Client {
public static void main(String[] args) {
// AccountService accountService = new AccountServiceImpl();
AccountService accountService = (AccountService)BeanFactory.getBean("accountService");
System.out.println(accountService);
}
}
工厂模式解决的问题:不再需要通过new方法来创建对象,可以通过反射和配置文件创建对象,如果类不存在是运行时报错,降低程序各类间的耦合度</