什么是框架?
所谓的框架就是程序的架子,在程序的架子中,搭建起程序的基本骨架,针对程序的通用问题给出了方便的解决方案,为开发人员能够基于框架快速地开发具体的应用程序程序提供帮助。
在java常见的框架有SSH框架(Struts2、Spring、Hibernate)和SSM框架(Spring、SpringMVC、MyBatis),在SSH框架中由于Struts2框架爆发过很多高危漏洞,使用起来有很大的安全隐患,所以随着SSM框架的流行SSH也随之过时。
Spring框架概述
Spring是一个Service层的框架,可以整合许多其他框架进行工作,Spring的主要技术是IOC(DI) 和 AOP
IOC(DI)-控制反转(依赖注入)
AOP-面向切面编程
如果想要下载Spring框架所需jar包,则登录https://spring.io进行下载即可。
注:为了帮助广大网友方便的学习SSM框架,可以发送邮箱1159768380@qq.com,这里笔者可以向大家提供了SSM相关的所有jar包。
配置Spring的约束
Spring本身是基于xml配置来工作的,在使用Spring的过程中不可避免的要编写大量的xml配置,所谓的xml的约束其实是一种限定xml文件写法的技术,主要分为两种:
DTD:通常文件后最为 .dtd
Schema:通常文件的后缀为 .xsd
Spring提供了Schema格式的约束,来限定Spring配置文件的写法,由于这个过程比较麻烦这里就不详细的介绍了。开发人员通常会将约束文件交给开发工具来管理,开发工具可以通过解析约束文件了解xml文件的写法,并在需要时为开发者提供标签支持。
Spring IOC
所谓的IOC称之为控制反转,简单来说就是将对象创建的权力及对象的生命周期的管理过程交给Spring框架来处理,从此在开发过程中不在需要关注对象的创建和生命周期的管理,这个由Spring框架管理对象创建和生命周期的机制称之为控制反转。下面我们可以通过一个小小的案例体会一下控制反转的使用。
1.创建一个java工程导入spring框架相关的jar包
2.创建Spring配置文件
Spring采用xml文件作为配置文件,xml文件名任意,但通常取名为applicationContext.xml。通常将该文件放置在类加载的目录(src目录)下。
3.创建bean类,并在spring中配置交由spring来管理。这里在src目录下创建了cn.springstudy.domain包下Person类。
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">
<bean id="person" class="cn.springstudy.domain.Person"></bean>
</beans>
4.在程序中通过Spring容器获取对象并使用
public class Test01 {
@Test
public void test01(){
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
Person person = (Person) context.getBean("person");
person.study();
}
}
打印结果为:
IOC的实现原理
在初始化一个Spring容器的时候,Spring会去解析指定的xml文件(applicationContext.xml)。当解析到<bean>时,会根据该标签中class属性指定全路径名,通过反射创建该类的对象,并将该对象存入Map中管理其中键就是该标签的id值,值就是该对象。
当通过getBean方法从容器中获取对象时,其实就是根据传入的条件在内置的Map中寻找是否有匹配的键值,如果有则将该键值对保存的对象返回,如果没有匹配是则报出异常。由此可以推断出:
1.默认情况下,多次获取同一个id的bean,得到的是同一个对象。
2.即使是同一个类,如果配置过多的<bean>标签且具有不同的id,每个id都会在内置的Map中有一个键值对,其中的值是这个类创建的不同的对象。
3.同一个<beans>标签下不允许配置过多个相同id的<bean>标签,如果启动则爆出异常。
IOC获取对象的方式
通过context.getBean()方法获取bean时,可以通过如下两种方法获取:
1.传入id值
2.传入class类型
通过class方法获取bean时,如果同一个类配置了过多的bean,则在获取时因为无法确定到底要获取哪一个bean会抛出异常。而id是唯一的,不存在这样的问题,所以在这里建议大家尽量使用id获取bean。SpringIOC在通过class获取bean时,如果找不到该类型的bean还回去检查是否存在该类型的子孙类型的bean,如果有则返回,如果找不到或者找到多个则会抛出异常。这个符合java变成思想中的多态。
Spring创建对象的方式
1.通过类的无参构造方法创建对象
在刚才的入门案例中使用的就是这种方法。当用最普通的方法配置一个<bean>时,默认采用的是无参构造创建对象。在Spring初始化容器时通过<bean>上的配置的class属性反射得到字节码对象,通过newInstance()创建对象。
Class c=Class.forName("类的全路径名称");
Object obj=c.newInstance();
这种方式下Spring创建对象,要求类必须有无参的构造,否则无法通过反射创建对象,会抛出异常。
2.通过静态工厂创建对象
很多的时候,我们面对的类是无法通过无参构造方法创建的,例如该类没有无参构造,或者是一种抽象类等等。此时无法要求Spring通过无参构造创建对象,此时可以使用静态工厂的方式创建对象。
a.创建静态工厂
/**
* 静态工厂
* 构造器私有化,保证工厂只有一个
* 提供静态的创建目标对象的方法,使用者直接通过类名调用此静态方法获取对象
*/
public class PersonStaticFactory {
private PersonStaticFactory() {
}
public static Person getInstance(){
return new Person("张三");
}
}
b.在xml文件中配置<bean>标签
<?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">
<!--静态工厂创建bean-->
<bean id="person" class="cn.springstudy.factory.PersonStaticFactory" factory-method="getInstance"/>
</beans>
c.测试同上
3.通过实例工厂创建对象
实例工厂也可以解决类是无法通过无参构造创建的问题,解决思路与静态工厂类似,只不过实例工厂提供的方法不是静态的。spring需要先创建实例工厂的对象,在调用实例工厂对象上指定的普通方法来创建对象。所以实例工厂也需要配置到spring中管理。
a.创建实例工厂
/**
* Person类的实例工厂
* 构造器不可以私有化,提供共有无参构造器
* 提供普通方法来创建目标对象
*/
public class PersonInstanceFactory {
public Person getInstance(){
return new Person("ls");
}
}
b.在xml文件中配置<bean>标签
<?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">
<!--实例工厂创建bean-->
<bean id="personInstanceFactory" class="cn.springstudy.factory.PersonInstanceFactory"></bean>
<bean id="person" factory-bean="personInstanceFactory" factory-method="getInstance"></bean>
</beans>
c.测试同上
4.Spring工厂创建对象
a.Spring内置了工厂接口,也可以通过实现这个接口来开发Spring工厂,通过这个工厂创建对象。
/**
* Spring工厂
* 必须实现FactoryBean的接口,并通过泛型指定要创建的对象类型
*/
public class PersonSpringFactory implements FactoryBean<Person> {
/**
* 获取目标对象
*/
@Override
public Person getObject() throws Exception {
return new Person("ww");
}
/**
* 获取目标对象类型
*/
@Override
public Class<?> getObjectType() {
return Person.class;
}
/**
* 是否以单例模式创建对象
*/
@Override
public boolean isSingleton() {
return true;
}
}
b.在xml文件中配置<bean>标签
<?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-->
<bean id="person" class="cn.springstudy.factory.PersonSpringFactory"></bean>
</beans>
c.测试同上
单例和多例
Spring容器管理的bean在默认情况下是单例的,也即,一个bean只会创建一个对象,存在内置的Map中,之后无论获取多少次该bean,都返回的是同一个对象。Spring默认采用单例方式,减少了对象的创建,从而减少了内存的消耗。但是实际开发中存在多例的需求,Spring也提供了选项可以将bean设置为多例模式。
<?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">
<!--
单例多例
singleton
单例模式
容器初始化时创建,存入容器内部map
之后无论获取多少次得到的都是同一个对象
prototype
多例模式
容器初始化时不创建
每次用到重新创建一个新的对象,此对象不会存入容器内map管理,其生命周期和普通的对象一样
每次获取拿到的都是一个全新的对象
-->
<bean id="person" class="cn.springstudy.domain.Person" scope="prototype"></bean>
</beans>
bean在单例模式下的生命周期
bean在单例模式下,Spring容器启动时解析xml文件发现bean标签后,直接创建bean的对象存入内部map中保存,此后无论调用多少次getBean()获取该bean都是从map中获取对象返回,一直都是同一个对象。此对象一直被Spring容器持有,直到容器退出时,随着容器的退出对象被销毁。
bean在多例模式下的生命周期
bean在多例模式,Spring容器启动时解析xml发现该bean标签后,只是将该bean进行管理,并不会创建对象,此后每次使用getBean()获取该bean时,Spring都取决于使用该对象的用户自己什么时候销毁该对象。
懒加载机制
Spring默认会在容器初始化的时候,解析xml文件,并将单例的bean创建保存到map中,这样的机制在bean比较少的时候问题不大,但一旦bean非常多时,Spring需要在启动的过程中花费大量的时间创建bean花费大量的内存空间存储bean,但这些bean可能很久都用不上,这种在启动时在时间和空间上浪费显然十分不值得。所以Spring提供了懒加载机制。所谓的懒加载机制就是可以规定指定的bean不在启动时立即创建,而是在后续第一次用到的时候才能创建,从而减轻在启动过程中对时间和内存的消耗。
xml文件配置:
1.为指定bean配置懒加载
<?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">
<bean id="stu" class="cn.springstudy.domain.Person" lazy-init="true"></bean>
</beans>
2.为全局配置懒加载
<?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"
default-lazy-init="true"
>
<bean id="stu" class="cn.springstudy.domain.Person" ></bean>
</beans>
注:如果同时设定全局和指定bean的懒加载,且配置不同,则对与该bean的局部配置覆盖全局配置。
配置初始化和销毁方法
在Spring中如果某个bean在初始化之后或者销毁之前要做一些额外的操作可以为该bean配置初始化和销毁方法,在这些方法中完成功能
a.创建方法类:
public class InitAndDestroy {
public void init(){
System.out.println("初始化方法");
}
public void destroy(){
System.out.println("销毁方法");
}
}
b.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"
default-lazy-init="true"
>
<bean id="initAndDestroy" class="cn.springstudy.domain.InitAndDestroy"
init-method="init" destroy-method="destroy"/>
</beans>
Spring中关键字方法的执行顺序
在Spring创建bean对象时,先创建对象(通过无参构造或者工厂),之后立即调用init()方法来执行初始化操作,之后此bean就可以拿来调用其他的普通方法,而在对象销毁之前。Spring容器最后会调用destroy()方法执行销毁操作。
由于Spring框架的内容较多,本文不能完全介绍完,后续还会更新。