Spring 是分层的 Java SE/EE 应用 full-stack 轻量级开源框架,以 IoC(Inverse Of Control:
反转控制)和 AOP(Aspect Oriented Programming:面向切面编程)为内核,提供了展现层 Spring
MVC 和持久层 Spring JDBC 以及业务层事务管理等众多的企业级应用技术,还能整合开源世界众多
著名的第三方框架和类库,逐渐成为使用最多的 Java EE 企业应用开源框架.。
方便解耦,简化开发:Spring就是一个大工厂,可以将所有对象的创建和依赖关系交给Spring来管理,避免硬编码所造成的过度程序耦合。
AOP编程的支持:Spring提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能。
声明式事务的支持:只需要通过配置就可以完成对事务的管理,而无需手动编程
方便程序的测试:Spring对Junit4支持,可以通过注解方便的测试Spring程序
方便集成各种优秀框架:Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如:Struts、Hibernate、Mybatis、Quartz等)的直接支持
降低JavaEE API的使用难度:Spring对JavaEE开发中非常难用的一些API(JDBC、JavaMail、远程调用等),都提供了封装,使这些API应用难度大大降低。
耦合:程序间的依赖关系
解耦:降低程序间的依赖关系
实际开发中:应该做到编译器不依赖,运行时才依赖。
解耦的思路:
总结:
耦合是影响软件复杂程度和设计质量的一个重要因素,在设计上我们应采用以下原则:如果模块间必须存在耦合,就尽量使用数据耦合,少用控制耦合,限制公共耦合的范围,尽量避免使用内容耦合。
JavaBean:Java语言中可重复使用的组件
工厂模式解耦:在实际开发中我们可以把三层的对象都使用配置文件配置起来,当启动服务器应用加载的时候,让一个类中的方法通过读取配置文件,把这些对象创建出来并存起来。在接下来的使用的时候,直接拿过来用就好了。那么,这个读取配置文件,创建和获取三层对象的类就是工厂。
当某一个接口删除后,编译不会报错,依然可以正常执行,但是会报异常“找不到文件”。
降低依赖关系可以用工厂模式来实现。工厂模式可以手写,但是这样开发效率很低,所以把工厂模式解耦都交给了Spring框架去做。
控制反转 IOC
控制反转把创建的对象的权力交给框架的重要特征,并非面向对象编程的专业术语,它包括依赖注入(DI)和依赖查找(DL)
作用:削减计算机程序的耦合(解除我们代码中的依赖关系)
package dao;
/**
* 账户的持久层接口
*/
public interface IAccountDao {
/**
* 模拟保存账户
*/
void saveAccount();
}
package dao.impl;
import dao.IAccountDao;
/**
* 账户的持久层实现类
*/
public class AccountDaoImpl implements IAccountDao {
public void saveAccount(){
System.out.println("保存了账户");
}
}
package factory;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
/**
* 一个创建Bean对象的工厂
*
* Bean:在计算机英语中,有可重用组件的含义。
* JavaBean:用java语言编写的可重用组件。
* javabean > 实体类
*
* 它就是创建我们的service和dao对象的。
*
* 第一个:需要一个配置文件来配置我们的service和dao
* 配置的内容:唯一标识=全限定类名(key=value)
* 第二个:通过读取配置文件中配置的内容,反射创建对象
*
* 我的配置文件可以是xml也可以是properties
*/
public class BeanFactory {
//定义一个Properties对象
private static Properties props;
//定义一个Map,用于存放我们要创建的对象。我们把它称之为容器
private static Map<String,Object> beans;
//使用静态代码块为Properties对象赋值
static {
try {
//实例化对象
props = new Properties();
//获取properties文件的流对象
InputStream in = BeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
props.load(in);
//实例化容器
beans = new HashMap<String,Object>();
//取出配置文件中所有的Key
Enumeration keys = props.keys();
//遍历枚举
while (keys.hasMoreElements()){
//取出每个Key
String key = keys.nextElement().toString();
//根据key获取value
String beanPath = props.getProperty(key);
//反射创建对象
Object value = Class.forName(beanPath).newInstance();
//把key和value存入容器中
beans.put(key,value);
}
}catch(Exception e){
throw new ExceptionInInitializerError("初始化properties失败!");
}
}
/**
* 根据bean的名称获取对象
* @param beanName
* @return
*/
public static Object getBean(String beanName){
return beans.get(beanName);
}
/**
* 根据Bean的名称获取bean对象
* @param beanName
* @return
public static Object getBean(String beanName){
Object bean = null;
try {
String beanPath = props.getProperty(beanName);
// System.out.println(beanPath);
bean = Class.forName(beanPath).newInstance();//每次都会调用默认构造函数创建对象
}catch (Exception e){
e.printStackTrace();
}
return bean;
}*/
}
package service;
/**
* 账户业务层的接口
*/
public interface IAccountService {
/**
* 模拟保存账户
*/
void saveAccount();
}
package service.impl;
import dao.IAccountDao;
import factory.BeanFactory;
import service.IAccountService;
/**
* 账户的业务层实现类
*/
public class AccountServiceImpl implements IAccountService {
// private IAccountDao accountDao = new AccountDaoImpl();
private IAccountDao accountDao = (IAccountDao) BeanFactory.getBean("accountDao");
// private int i = 1;
public void saveAccount(){
int i = 1;
accountDao.saveAccount();
System.out.println(i);
i++;
}
}
accountService=com.itheima.service.impl.AccountServiceImpl
accountDao=com.itheima.dao.impl.AccountDaoImpl
package ui;
import factory.BeanFactory;
import service.IAccountService;
/**
* 模拟一个表现层,用于调用业务层
*/
public class Client {
public static void main(String[] args) {
//IAccountService as = new AccountServiceImpl();
for(int i=0;i<5;i++) {
IAccountService as = (IAccountService) BeanFactory.getBean("accountService");
System.out.println(as);
as.saveAccount();
}
}
}
运行结果:
通过手写工厂模式清楚的展现了上述图中的工厂代理模式,这种模式可以很有效的降低程序之间的依赖关系,sping就是采用了这种模式来达到解耦的效果。
官网:http://spring.io/
下载地址:
http://repo.springsource.org/libs-release-local/org/springframework/spring
ApplicationContext的三个常用实现类:
ClassPathXmlApplicationContext:它可以加载类路径下的配置文件,要求配置文件必须在类路径下。不在的话,加载不了。(更常用)
FileSystemXmlApplicationContext:它可以加载磁盘任意路径下的配置文件(必须有访问权限)
AnnotationConfigApplicationContext:它是用于读取注解创建容器的。
核心容器的两个接口引发出的问题:
ApplicationContext: 单例对象适用 采用此接口
它在构建核心容器时,创建对象采取的策略是采用立即加载的方式。也就是说,只要一读取完配置文件马上就创建配置文件中配置的对象。
BeanFactory: 多例对象使用
它在构建核心容器时,创建对象采取的策略是采用延迟加载的方式。也就是说,什么时候根据id获取对象了,什么时候才真正的创建对象。
什么是单例和多例
单例:创建对象时在不同的地方获取的Bean对象是同一个
多例:创建对象时在不同的地方获取的Bean对象是不同的对象
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">bean>
<bean id="instanceFactory" class="com.itheima.factory.InstanceFactory">bean>
<bean id="accountService" factory-bean="instanceFactory" factory-method="getAccountService">bean>
<bean id="accountService" class="com.itheima.factory.StaticFactory" factory-method="getAccountService">bean>
bean标签的scope属性:
作用:用于指定bean的作用范围
取值: 常用的就是单例的和多例的
org.springframework
spring-context
5.0.2.RELEASE
<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="service.impl.UserServiceImpl" scope="singleton"
init-method="init" destroy-method="destroy">bean>
<bean id="userDao" class="dao.impl.AccountDaoImpl">bean>
beans>
package service;/*
*Created by tao on 2020-03-29.
*/
public interface UserService {
/**
* 模拟保存账户
*/
void saveAccount();
}
UserServiceImpl
package service.impl;/*
*Created by tao on 2020-03-29.
*/
import service.UserService;
public class UserServiceImpl implements UserService {
public UserServiceImpl() {
System.out.println("对象创建了");
}
public void saveAccount() {
System.out.println("service中的saveAccount方法执行了。。。");
}
public void init() {
System.out.println("对象初始化了。。。");
}
public void destroy() {
System.out.println("对象销毁了。。。");
}
}
package test;/*
*Created by tao on 2020-03-29.
*/
import org.springframework.context.support.ClassPathXmlApplicationContext;
import service.UserService;
public class Client {
public static void main(String[] args) {
//1.获取核心容器对象
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
//2.根据id获取Bean对象
UserService us1 = (UserService) ac.getBean("userService");
UserService us2 = (UserService) ac.getBean("userService");
System.out.println(us1);
System.out.println(us1 == us2);
us1.saveAccount();
}
}