Spring是一个轻量级控制反转(IoC)和面向切面(AOP)的容器框架
IoC控制反转,当A类依赖B类时(A类需要B类的实例化对象)在没有控制反转前需要A类主动去创建B类的对象(new B类对象)。控制反转后,B类在初始化之前,B类所需要的对象就由容器创建好了并存储在容器中,当B类需要使用A类的对象时再由容器传递给B类。可以降低程序之间的耦合度。
- 降低耦合度的方法
1.通过反射来加载要实例化的类
2.把完整的包名+类名放入到配置文件 xml
手写一个简单的ioc
如test依赖service,sercice依赖dao
先把需要使用到的对象记录在一个文件里,test使用service的对象,service使用dao的对象
定义一个工厂,其实是一个容器,把需要使用到的对象都放到这个容器里,当有对象使用的需求时直接从容器里取
public class Factory {
private static Map<String,Object> map;
static {
try {
//把记录需要使用的类的文件加载进来
InputStream is = Class.forName("com.fyj.factory.Factory").getClassLoader().getResourceAsStream("IocConfig.properties");
Properties properties = new Properties();
properties.load(is);
//用map作为容器存储每个对象
map = new HashMap<String, Object>();
Enumeration enumeration = properties.keys();
while (enumeration.hasMoreElements()){
String key = (String) enumeration.nextElement();
String val = properties.getProperty(key);
//通过反射实例化对象
Object object = Class.forName(val).newInstance();
map.put(key,object);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
//取出对象
public static Object get(String key){
return map.get(key);
}
}
dao无需实例化对象
public class IocTestDaoImpl implements IocTestDao {
public void show() {
System.out.println("yes");
}
}
service需要实例化dao的对象,所以从factory中取出dao的实例对象
public class IocTestServiceImpl implements IocTestService {
public void show() {
IocTestDaoImpl iocTestDao = (IocTestDaoImpl)Factory.get("dao");
iocTestDao.show();
}
}
test需要service的对象,从factory中取
public class IocTest {
@Test
public void Test1(){
IocTestServiceImpl iocTestService = (IocTestServiceImpl)Factory.get("service");
iocTestService.show();
}
}
spring IOC
- spring IOC使用的小案例
1.pom文件中添加依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
public class Factory {
public TestClass getTestClass(){
return new TestClass(2);
}
}
2.编写xml文件,即需要使用到的实例化的类都写到里面
<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">
<!-- 实例化名为Factory对象时,会使用Factory的无参构造-->
<bean id="Factory1" class="Factory" ></bean>
<!-- 实例化名为Factory1的对象,并使用getTestClass方法,getTestClass实例化出TestClass对象-->
<bean id="TestClassByFac" factory-bean="Factory1" factory-method="getTestClass"></bean>
</beans>
3.使用
public class Test {
public static void main(String[] args) {
ApplicationContext app = new ClassPathXmlApplicationContext("config.xml");
Factory factory = (Factory) app.getBean("Factory1");
TestClass r = app.getBean("TestClassByFac",TestClass.class);
r.show();
}
}
-
相关API
BeanFactory 是spring的顶级父类,提供了一些spring IO的基础代码,我们使用的是其派生接口 ApplicationContext
ApplicationContext 其实就是对 BeanFactory 封装以及加强(ioc 的代码有封装,日志的处理都有相关的封装 )-
BeanFactory和ApplicationContext 区别
ApplicationContext 采用的是立即加载来创建对象 也就是spring容器初始化 创建spring管理的所有的对象 (单例) ,BeanFactory (多例) 使用的是延迟加载的方式来创建对象 在具体使用的时候由容器创建对象 -
ApplicationContext的3个实现类
类名 作用 ClassPathXmlApplicationContext 通过类路径来加载配置文件 FileSystemXmlApplicationContext 根据(绝对路径)路径来加载配置文件 AnnotationConfigApplicationContext 使用注解的方式来加载配置文件 -
-
spring对bean的管理
spring提供了scope属性来对bean的属性进行设置
属性 | - |
---|---|
singleton | 单例 |
prototype | 多例 |
request | 用在web项目,对象存放容器中,并且放到request 作用域中 |
session | 用在web项目,对象存放容器中,并且放到session作用域中 |
globaisession | 在 web的分布式项目,存在全局的session中 |
spring的依赖注入
依赖注入,获取到具有指定参数的对象,依赖注入两种方式:构造方法、set 注入
<bean id="stu" class="com.fyj.bean.Student">
<constructor-arg name="uid" value="1"></constructor-arg>
<constructor-arg name="uname" value="lisi"></constructor-arg>
<constructor-arg name="upwd" value="123"></constructor-arg>
<constructor-arg name="usex" value="男"></constructor-arg>
</bean>
<bean id="stu0" class="com.fyj.bean.Student">
<property name="uid" value="2"></property>
<property name="usex" value="女"></property>
</bean>
property用于set注入,set注入是根据属性的set方法来进行赋值的,name需要和set方法所指的名称保持一致,如类中的方法setUpwd() 和 name=Upwd 对应
constructor用于构造方法注入name名称和构造方法中参数的名称一致,构造方法注入时,参数个数需要和构造方法中的个数相同。
当需要注入引用数据的类型时,需要先获得其实体Bean在通过id注入,注入时使用ref而非value,如给Date类的成员变量赋值
<bean id="date" class="java.util.Date"></bean>
<bean id="stu0" class="com.fyj.bean.Student">
<property name="date" ref="date"></property>
</bean>
set注入的另一种形式是使用p标签,如下
<bean id="date" class="java.util.Date"></bean>
<bean id="stu0" class="com.fyj.bean.Student" p:usex="男" p:date-ref="date"></bean>
使用时可以通过ApplicationContext 根据bean的id来获取对象
ApplicationContext app = new ClassPathXmlApplicationContext("config.xml");
User user = app.getBean("stu0",Student.class);
注入集合相关的数据
<bean id="stu0" class="com.fyj.bean.Student">
<property name="array">
<array>
<value>1</value>
<value>2</value>
</array>
</property>
<property name="list">
<list>
<value>1</value>
<value>2</value>
<value>3</value>
</list>
</property>
<property name="map">
<map>
<entry key="a" value="1"></entry>
<entry key="b" value="2"></entry>
</map>
</property>
<property name="properties">
<props>
<prop key="a">1</prop>
<prop key="b">2</prop>
</props>
</property>
</bean>
配置文件模块化
多个配置信息写在一个xml文件中时结构清晰度较差,可以设置一个主要的xml文件,在这个xml文件中引入其他的xml文件。如
<import resource="classpath:User.xml" ></import>
注意:当主文件中的bean的id,和被引入的文件中的bean的id重名时,主文件的bean会覆盖背引入文件的bean
通过注解进行依赖注入
-
步骤
1.需要先在pom文件中添加依赖<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.2.RELEASE</version> </dependency>
2.配置文件的dtd约束为
<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:component-scan base-package="com.fyj"/>
3.添加注解
@Component 用来实例化对象,把当前对象给spring来进行管理(在类上进行修饰),有一个value属性,默认值是当前类的(首字母小写)名称
@Repository @Service @Controller 三者和 @Component 功能完全相同,分别用于持久层、业务层、视图层
@Autowired 用来给对象中的类进行注入,一般使用的时候在成员变量上。注入时是案类型注入,当spring中有多个匹配的类时,就会报错。可以添加@Qualifier来指定名称进行注入。
使用时还是通过app.getBean获取bean来使用