一、程序的耦合和解耦
1、耦合(程序间的依赖关系)
a、类之间的依赖
b、方法间的依赖
2、解耦(应该做到编译器不依赖,运行时依赖)
a、降低程序间的依赖关系
b、思路
1,使用反射来创建对象,而避免使用new关键字
2,通过读取配置文件来获取要创建的对象全限定类名
3、解决方案
a、创建Bean工厂(bean:可重用组件)
/*
例如:service和dao对象
service 依赖于 dao
两者的impl也依赖于本体
1,需要一个配置文件来配置我们的service和dao配置的内容:唯一标识=全限定类名(key=value)
2,通过读取配置文件中的配置的内容,反射创建
配置文件可为xml或properties
*/
//配置bean.properties
accountService=com.learn.service.impl.AccountServiceImpl
accountDao=com.learn.dao.impl.accountDaoImpl
//编写BeanFactory
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<String> 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("初始化失败");
}
}
//根据Bean名称获取bean对象
public static Object getBean(String beanName){
return beans.get(beanName);
}
}
//则再客户端或者实现类中,可用BeanFactory.getBean("配置的名称")
IAccountService as = BeanFactory.getBean("accountService");
2、Spring的IoC解决程序耦合
a、概念(控制反转(IoC)把创建对象的权利交给框架)
b、主要jar包(jar包依赖关系同)
1,spring-bean-5.0.2.RELEASE.jar
2,spring-context-5.0.2.RELEASE.jar
3,spring-core-5.0.2.RELEASE.jar
4,spring-expression-5.0.2.RELEASE.jar
5,spring-aop-5.0.2.RELEASE.jar
6,spring-jcl-5.0.2.RELEASE.jar
c、基本环境搭建
//配置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">
//把对象的创建交给spring来管理
<bean id="accountService" class="com.learn.service.impl.AccountServiceImpl">
</bean>
<bean id="accountDao" class="com.learn.dao.impl.AccountDaoImpl">
</bean>
</beans>
//获取spring的IoC核心容器,并根据id获取对象
public class Client{
public static void main(){
/*
ApplicationContext:在构建核心容器时,创建对象采取的策略是立即加载的方式
BeanFactory:在构建核心容器时,创建对象采取的策略是延迟加载的方式(当根据id获取对象时,才真正创建对象)
获取核心容器对象
*/
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
/*
根据id获取Bean对象
可用(IAccountService)ac.getBean("accountService")进行强转
ad.getBean("accountDao",IAccountDao.class)通过字节码进行强转
*/
IAccountService as = (IAccountService)ac.getBean("accountService");
IAccountDao ad = ad.getBean("accountDao",IAccountDao.class);
System.out.println("as="+as+"ad="+ad);
}
}
d、spring对bean的管理细节
1,创建bean的三种方式
//使用默认构造函数创建
<bean id="accountService" class="com.learn.service.impl.AccountServiceImpl"></bean>
/*
创建一个实例化工厂类,在里面定义getAccountService方法
使用普通工厂中的方法创建对象(使用类中的方法创建对象,并存入spring容器)
*/
<bean id="instanceFactory" class="com.learn.factory.InstanceFactory"></bean>
<bean id="accountService" factory-bean="instanceFactory" factory-method="getAccountService"></bean>
/*
创建一个实例化工厂类,在里面定义getAccountService的静态方法
使用普通工厂中的方法创建对象(使用类中的方法创建对象,并存入spring容器)
*/
<bean id="accountService" class="com.learn.factory.StaticFactory"
factory-method="getAccountService"></bean>
2,bean的作用范围(使用bean标签里的scope标签)
①:取值,通常是单例或者多例
singleton | 单例的(默认值) |
---|---|
prototype | 多例的 |
request | 作用于web应用的请求范围 |
session | 作用于web应用的会话范围 |
golbal-session | 作用于集群环境会话范围(全局会话范围),当不是集群环境时,它就是session |
3,生命周期 |
①:单例对象
出生 | 当容器创建时对象出生 |
---|---|
活着 | 只要容器还在,对象就一直活着 |
死亡 | 容器销毁,对象消亡 |
总结 | 单例对象的生命周期和容器相同 |
②:多例对象
出生 | 当我们使用对象时,spring框架为我们创建 |
---|---|
活着 | 对象使用过程中一直活着 |
死亡 | 对象长时间不用,且没有别的对象应用时,由java的垃圾回收器回收 |
3、依赖注入
a、概念
1,在当前类需要用到其他类的对象,由spring为我们提供,我们只需要在配置文件中说明
2,依赖关系的维护(依赖注入)
3,依赖关系的管理(交给spring来维护)
4,能注入的数据类型
①:基本数据类型和String
②:其他bean类型(在配置文件中或者注解配置过的bean)
③:复杂关系/集合类型
5,注入方式
①:构造函数提供
②:set方法提供(主要方式)
③:注解提供(主要方式)
b、set方法注入
/*
property标签属性:
name:用于指定注入时所调用的set方法
value:用于提供基本类型和String类型的数据
ref:用于指定其他的bean类型数据。
*/
//配置的日期对象
<bean id="now" class="java.util.Date">
<bean id="accountService" class=""com.learn.service.impl.AccountServiceImpl>
<property name="name" value="zhangsan"></property>
<property name="age" value="18"></property>
<property name="birthday" ref="now"></property>
</bean>
/*
复杂类型的注入/集合类型的注入
list结构集合注入的标签:
list array set
Map结构集合注入的标签:
map props
结构相同时,标签可以互换
*/
<bean id="accountService" class=""com.learn.service.impl.AccountServiceImpl>
//list
<property name="myList">
<list>
<value>aaa</value>
<value>bbb</value>
</list>
</property>
//Map结构
<property name="myProps">
<map>
<entry key="testA" value="aaa"></entry>
<entry key="testB" value="bbb"></entry>
</map>
</property>
</bean>
二、Spring基于注解配置IoC
1、常用注解
注解名称 | 作用 |
---|---|
@Component | 用于把当前类对象存入spring容器中 |
@Autowired | 自动按照类型注入,只要容器中有唯一匹配的bean对象,就可以成功注入 |
@Qualifier | 在按照类中注入的基础之上,再按名称注入 |
@Value | 用于指定注入基本类型和String类型的数据 |
@Scope | 用于指定bean的作用范围(常用取值:singleton prototype) |
@PreDestory | 指定销毁方法 |
@PostConstruct | 用于指定初始化方法) |
只能通过bean.xml配置 | 集合类型 |
a、@Component
1,作用:用于把当前类对象存入spring容器中
2,属性:value用于指定bean的id(默认为当前类名且首字母改小写)
3,相同作用与属性的注解(Spring框架提供三层使用的注解)
①:Controller 表现层
②:Service 业务层
③:Repository 持久层
b、@Qualifier
1,配合@Autowired对类进行精确的注入
//注入accountDao1
@Autowired
@Qualifier("accountDao1")
private IAccountDao accountDao;
c、@Resource
@Resource("accountDao1")
private IAccountDao accountDao;
d、@Value
①:可以使用Spring中的spEL(el表达式)
②:SpEL写法:$(表达式)
2、环境搭建
/*
配置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"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
//告知spring在创建容器时要扫描的包,配置所需要的的标签不只是在beans的约束中,
//而是一个名为context名称空间和约束中
<context:component-scan base-packing="com.learn"></context:component-scan>
</beans>
//配置AccountServiceImpl
@Component
public class AccountService implenments IAccountService{
@Autowired
private IAccountDao accountDao;
public AccountServiceImpl(){
System.out.println("对象创建完成")
}
}
//获取spring的IoC核心容器,并根据id获取对象
public class Client{
public static void main(){
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
//根据id获取Bean对象
IAccountService as = (IAccountService)ac.getBean("accountServiceImpl");
System.out.println("as="+as);
}
}