这段时间对于SSM处于复习阶段,结合自己课上的新一轮学习,将这部分内容再次复习整理一遍
框架
- 框架概述
框架即是一种半成品,已经对基础的代码进行了封装并提供相应的API,开发者在使用框架是直接调用封装好的api可以省去很多代码编写,从而提高工作效率和开发速度。 - 常见的框架
- SSH
- SSM
Spring
Spring框架概述
Spring 是个java企业级应用的开源开发框架。Spring主要用来开发Java应用,但是有些扩展是针对构建J2EE平台的web应用。Spring 框架目标是简化Java企业级应用开发,并通过POJO为基础的编程模型促进良好的编程习惯。
Spring是噫Service层框架,可以整合许多其它框架进行工作
- IOC(DI):控制反转-依赖注入
所谓IOC称之为控制反转,简单来说就是将对象的创建的权利及对象的生命周期的管理过程交给Spring框架来处理,从此在开发过程中不在需要关注对象的创建和生命周期的管理,而是需要时由Spring框架提供,这个由SPringle框架管理对象创建和生命周期的机制称之为控制反转。 - AOP:面向切面编程
IOC的实现原理
在初始化一个Spring容器时,Spring会去解析指定xml文件,当解析到其中的标签时,会根据该标签中的class属性指定类的全路径名,通过反射创建该类的对象,并将该对象存入内置的Map中管理。其中键就是该标签的值,值就是改对象。
之后,当通过getBean方法来从容器中获取对象时,其实就是根据传入的条件在内置的Map中寻找是否有匹配的键值,如果有则将该兼职对中保存的值返回,如果没有匹配到则抛出异常
第一个Spring的程序
- 首先我们需要创建一个applicationContext的Spring配置文件
<!--配置bean-->
<bean id="helloWorld" class="com.zhe.HelloWorld">
<property name="name" value="Spring"></property>
</bean>
注意:IDEA在创建的时候需要注意会提示Application context not configured for this file,这里我们需要在moudles中把这个spring的配置文件给配置进去。
- 获取bean实例
//1.创建spring的IOC容器对象
//ApplicationContext 代表IOC容器
//ClassPathXmlApplicationContext 是ApplicationContext 接口的实现类。该实现类从类路径下来加载配置文件
ApplicationContext ctx=new ClassPathXmlApplicationContext("META-INF/applicationContext.xml");
//2.从IOC中获取Bean实例
HelloWorld helloWorld= (HelloWorld) ctx.getBean("helloWorld");
helloWorld.hello();
注意:
1.ClassPathXmlApplicationContext的加载机制需要留意。这里我是放在src\main\resources\META-INF下的,一开始类加载器并不能直接找到spring的配置文件,报错。修改成META-INF/applicationContext.xml后可以正常运行。(留意反射机制)
2.如果只创建IOC容器,在内部,spring会帮我们调用在bean中配置的类的构造器,同时调用set方法对于属性进行赋值。
很明显,这种获取bean是使用的反射机制,而且它需要类给它提供无参构造器,但是有时候不一定有无参构造器,那么这种时候我们就可以用工厂方法来获取bean的实例。
静态工厂方法
首先我们可以使用的是静态工厂方法,这种方法是直接调用某一个类的静态方法就可以返回bean的实例,注意静态工厂方法使用的不是创建本身类对象调用其方法,而是在创建出一个静态方法对象
public class StaticCarFactory {
private static Map<String, Car> cars=new HashMap<String,Car>();
static {
cars.put("audi", new Car("audi",300000));
cars.put("ford", new Car("ford",400000));
}
//静态工厂法
public static Car getCar(String name) {
return cars.get(name);
}
}
<!-- 通过静态工厂方法来配置bean 注意不是配置静态工厂方法实例而是配置bean实例 -->
<bean id="car1" class="com.zhe.spring.beans.factory.StaticCarFactory" factory-method="getCar">
<!--
class属性:指向静态工厂方法的全类名
factory-method:指向静态工厂方法的名字
constructor-arg:如果工厂方法需要传入参数,则使用constructor-arg来配置参数
-->
<constructor-arg value="audi"></constructor-arg>
</bean>
实例工厂方法
实例工厂方法,即实例的工厂的方法,需要创建工厂本身。在调用工厂的实例方法来返回bean的实例
public class InstanceCarFactory {
private Map<String, Car> cars=null;
public InstanceCarFactory() {
// TODO Auto-generated constructor stub
cars=new HashMap<String,Car>();
cars.put("audi", new Car("audi",300000));
cars.put("ford", new Car("ford",400000));
}
public Car getCar(String brand) {
return cars.get(brand);
}
}
这种方法可以很明显的看出来,在创建的时候new出了一个对象,就是在堆内存中开辟中了一块空间为了bean的加载。
<!-- 配置工厂的实例 -->
<bean id="carFactory" class="com.zhe.spring.beans.factory.InstanceCarFactory"></bean>
<!-- 通过实例工厂的方法来配置bean -->
<bean id="car2" factory-bean="carFactory" factory-method="getCar">
<constructor-arg value="ford"></constructor-arg>
</bean>
实例工厂方法,重点是实例的创建,那么在bean中为了突出实例的创建,便是一个bean的创建。
所以相比于静态工厂方法,的数量是2而不是1。
FactoryBean方法
这种方法就是使用spring下的方式来获取对象,那么首先要对应的类实现FactoryBean接口接口
public class CarFactoryBean implements FactoryBean<Car> {
private String brand;
public void setBrand(String brand) {
this.brand=brand;
}
//返回bean的对象
@Override
public Car getObject() throws Exception {
// TODO Auto-generated method stub
return new Car(brand,500000);
}
/**
* 返回bean类型
*/
@Override
public Class<?> getObjectType() {
// TODO Auto-generated method stub
return Car.class;
}
//是否返回单例模式
@Override
public boolean isSingleton() {
// TODO Auto-generated method stub
return true;
}
}
实现接口之后就必须要实现对应的方法,三个方法都对应了不同的信息,然后就需要在applicationContext中进行配置
<!--
通过FactoryBean来配置Bean的实例
class:指向FactoryBean的全类名
property:配置FactoryBean的属性
但实际返回的实例确实FactoryBean的getObject()方法返回实例
-->
<bean id="car" class="com.zhe.spring.beans.factorybean.CarFactoryBean">
<property name="brand" value="BMW"></property>
</bean>
综合上面的三种工厂方法和无参构造,很明显无参构造是最方便的,那么无参构造需要的就是无参构造器,那么为了代码规范,以后在写类的时候就一定要记得提供无参构造和含参数构造,这是为了以后的代码规范问题
初始化和销毁时候的属性配置
- init-method
- destroy-method
执行顺序
在spring创建bean对象时,先创建对象(通过无参构造或者工厂),之后立即调用init方法来执行初始化操作,之后此bean就可以调用其它普通方法,而在对象销毁之前,spring容器调用其destroy方法来执行销毁操作。
DI依赖注入
property注入
- 属性注入即通过setter方法注入Bean的属性值或依赖的对象
- 属性注入使用元素,使用name属性指定Bean的属性名称,value属性或子节点指定属性值
- 属性注入是实际应用中最常用的注入方式
自动装配
byName和byType
- spring IOC容器可以自动装配Bean,需要做的仅仅是在的autowire属性里指定自动装配的模式
- byType(根据类型装配):若IOC容器中有多个与目标bean类型一致的bean,在这种情况下,spring将无法判定哪个bean最适合该属性,所以不能执行自动装配
- byName(根据名称自动装配):必须将目标bean的名称和属性名设置的完全相同
- constructor(根据构造器自动装配):当bean存在多个构造器时候,这种自动装配的方式会很复杂,不推荐使用
<!-- 可以使用auto wire属性指定装备的方式,
byname 根据bean的名字和当前bean的setter风格的属性名进行自动装配, 若有匹配的,则进行自动装配,若没有匹配的,则不装配
bytype 根据bean的类型和当前bean的属性的类型进行自动装配 。若IOC容器中有一个以上的类型匹配bean,则抛出异常
-->
<bean id="person" class="com.zhe.spring.beans.autowire.Person"
p:name="Tom" autowire="byName"></bean>
缺点:
- 在bean配置文件中设置文件里设置autowire属性进行自动装配将会装配bean的所有属性。然而,若只希望装配个别属性时,autowire就不够灵活
- autowire要么根据类型装配,要么根据名称装配,不能二者兼而有之
- 一般情况下,在实际的项目中很少使用自动装配功能,因为和自动装配功能带来的好处相比,清晰的文档更有说服力一点
- 在整合第三方框架的时候会更多的用到autowire
全局自动装配
//辅助使用注解的方式
<context:component-scan base-package="com.zhe"/>
构造方法注入
<!-- 通过构造方法来配置bean的属性
value指定传入的值,而index指定传入的顺序和类型
-->
<bean id="car" class="com.zhe.spring.bean.Car">
<constructor-arg value="Audi" index="0"></constructor-arg>
<constructor-arg value="ShangHai" index="1"></constructor-arg>
<constructor-arg value="300000" type="double"></constructor-arg>
</bean>
注意:
使用这种方式注入,可能会出现这样的问题:
构造方法不止一个,即参数列表的不同,如果不加以限定,就会已错误的方式传入,这种情况下需要我们关注到参数列表的属性,以类似type="java.lang.String"的限定方式保证数据的完整性。
<!-- 使用构造器注入属性值可以指定参数的位置和参数的类型 以次来区分重载构造器 -->
<bean id="car2" class="com.zhe.spring.bean.Car">
<constructor-arg value="Baoma" type="java.lang.String"></constructor-arg>
<!-- 如果包含特殊字符,在value里用<![CDATA ]> 包裹起来 -->
<!-- 属性值可以使用value直接进行配置 -->
<constructor-arg type="java.lang.String">
<value><![CDATA[<ShangHai^>]]></value>
</constructor-arg>
<constructor-arg type="int">
<value>240</value>
</constructor-arg>
</bean>