一、初始Spring
1.作者
Rod Johnson(音乐和数学博士)。Expert One To One。这是Spring的前身。
2.概述
Spring是一个轻量级的DI/IoC和AOP容器框架,存在的目的是用于构建轻量级的J2EE应用。
Spring以一种非侵入式的方式管理你的代码,Spring提倡最少“侵入”,这也就意味着你可在适当的时候使用或者不用Spring
3.Spring的优势
Spring是一个轻量级的框架
更好的提供了事务的管理
更强大的框架支持、方便集成其他框架
低侵入、低耦合(降低组件之间的耦合度,实现软件各层之间的解耦)
4.构成
二、IoC
1.引出IoC
修改前代码
Dao接口
public interface UserDao {
public void getUser();
}
Dao实现
public class MySqlUserDaoImpl implements UserDao {
@Override
public void getUser() {
System.out.println("mySql读取User数据。。。");
}
}
public class OracleUserDaoImpl implements UserDao {
@Override
public void getUser() {
System.out.println("Oracle读取User数据。。。");
}
}
service
public class UserService {
//UserDao dao = new MySqlUserDaoImpl();
UserDao dao = new OracleUserDaoImpl();
public void getUser(){
dao.getUser();
}
}
service层与dao层耦合度非常的高,层与层之间耦合度比较大,每次需求的变化都需要代码的修改。程序的灵活性很差。
修改代码后
Dao接口
public interface UserDao {
public void getUser();
}
Dao实现
public class MySqlUserDaoImpl implements UserDao {
@Override
public void getUser() {
System.out.println("mySql读取User数据。。。");
}
}
public class OracleUserDaoImpl implements UserDao {
@Override
public void getUser() {
System.out.println("Oracle读取User数据。。。");
}
}
service
UserDao dao = null;
public void getUser(){
dao.getUser();
}
public void setDao(UserDao dao) {
this.dao = dao;
}
Test
public static void main(String[] args) {
UserService service = new UserService();
service.setDao(new MySqlUserDaoImpl());
service.getUser();
System.out.println("--------------------");
service.setDao(new OracleUserDaoImpl());
service.getUser();
}
由以前的service主动创建对象变为现在的service被动接受对象。这种变化更好的分离了层与层之间的关系,同时降低了耦合度。
这种反转我们就可以成为控制反转。这种思想也就是IOC前身。
2.概述
不是一种技术,而是一种设计思想(类似于MVC)。就是原本在应用程序中我们手动创建对象的控制权,交由Spring框架管理,也就是创建对象的控制权反转到了Spring。
控制反转也称为依赖注入(Dependency Injection),其实控制反转和依赖注入是同一个概念,只是角度不同。
控制反转实际上涉及到两个行为,一个是控制,一个是反转。
控制:指由谁来创建对象
反转:指反过来了,由Spring创建对象,应用程序被动接受。以前应用程序是主动创建,现在应用程序被动接受。
3.事例
1).Vo类
public class User {
private String name;
public void setName(String name) {
this.name = name;
}
public void show(){
System.out.println("name :" + name);
}
}
1).实现步骤
a、准备Jar包
b、创建配置文件
创建一个名为beans.xml的配置文件(配置文件的名称可以是其的)
拷贝文件头(xsd-configuration.html)
配置beans.xml
<bean id="user" class="cn.bdqn.vo.User">
<property name="name" value="Mike"></property>
</bean>
c、创建对象
public class Test {
public static void main(String[] args) {
//加载配置文件
ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
//解析并实例化bean对象
User user = (User)ac.getBean("user");
//使用bean对象
user.show();
}
}
4.思考
1)、对象是谁创建的?
对象是由Spring创建的,具体的说应该是Spring中的BeanFactory创建的。
2)、对象的属性是怎么赋值的?
在创建Bean对象的同时,Spring就会自动将Property的属性值注入到Bean对象的属性上。
三、IoC容器和bean的创建时机
1.IoC容器
BeanFactory:这个接口是spring中最底层的接口,只提供了最简单的IoC功能(创建bean,获取bean,销毁bean)
在一般的应用当中,一般不使用BeanFactory;推荐用ApplicationContext(应用上下文);ApplicationContext继承了BeanFactory,提供了基本的IoC功能;
ApplicationContext还提供了其他功能:1,支持国际化;
2,支持消息机制;
3,支持统一的资源加载;
4,支持AOP功能;
2.bean的创建时机
1.用ApplicationContext创建对象
ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
System.out.println("-------------------------------");
HelloWorld hello = ac.getBean("helloWorld",HelloWorld.class);
hello.show();
结果
2.用BeanFactory创建对象
Resource resource = new ClassPathResource("beans.xml");
BeanFactory bf = new XmlBeanFactory(resource);
System.out.println("-------------------------------");
HelloWorld hello = bf.getBean("helloWorld",HelloWorld.class);
hello.show();
结果
3.总结
1.ApplicationContext在加载的时候就会创建所有的bean (Web应用建议)
2.BeanFactory需要等到拿bean的时候才会创建bean(延迟初始化)(桌面程序)
3.使用applicationContext如何进行延迟初始化?
<bean id="helloWorld" class="cn.bdqn.vo.HelloWorld" lazy-init="default" />
lazy-init的取值有default、false、true。其中default、false和不写lazy-init作用相同都是不支持延迟初始化
针对于当前xml中所有的bean。<beans default-lazy-init="default | false | true">
四、bean的作用域、初始化和销毁
1.bean的作用域
<bean id="" class="" scope="作用域"/>
singleton :单例 ,在Spring IoC容器中仅存在一个Bean实例 (默认的scope)
单例方式进行bean对象的实例化ClassPathXmlApplicationContext加载时对象就被实例化了(每用一次实例化一个对象)、调用getBean()时将不再创建对象
prototype: 多例 ,每次从容器中调用Bean时,都返回一个新的实例.
ClassPathXmlApplicationContext加载时对象不会被实例化、每次调用getBean()时才进行对象的实例化
总是会延迟初始化lazy-init无论为何值。request: 用于web开发,将Bean放入request范围 ,request.setAttribute(“xxx”) , 在同一个request 得同一个Bean
session: 用于web开发,将Bean 放入Session范围,在同一个Session 获得同一个Bean
总结:
在开发中主要使用 scope=”singleton”、 scope=”prototype”.对于MVC中的Action使用prototype类型,其他使用singleton
2.bean的初始化和销毁
比如DataSource,SessionFactory最终都需要关闭资源:在Bean销毁之前,都要调用close方法.
<bean id="someBean" class="......" init-method="该类中初始化方法名" destroy-method="该类中销毁方法名">
</bean>init-method:bean生命周期初始化方法,对象创建后就进行调用
destroy-method:容器被销毁的时候,如果bean被容器管理,会调用该方法。
注意:
如果bean的scope=”prototype”,那么容器只负责创建和初始化,它并不会被spring容器管理销毁。
不使用Spring测试:Spring容器非正常关闭:
没有调用destroy方法。
解决一:
在applicationContext中有一个子类AbstractApplicationContext、提供了close()方法,而在applicationContext中是不存在的。
@Test
public void test1(){
AbstractApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
System.out.println("--------------");
HelloWorld hello1 = ac.getBean("helloWorld",HelloWorld.class);
System.out.println(hello1);
ac.close();
}
解决二:
更好的方式:把当前Spring线程作为JVM线程的子线程。也就是说Spring没有运行玩JVM就不会终止。
@Test
public void test1(){
AbstractApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
System.out.println("--------------");
HelloWorld hello1 = ac.getBean("helloWorld",HelloWorld.class);
System.out.println(hello1);
ac.registerShutdownHook();
}
五、Spring创建对象
1.对象的创建方式
1.构造器实例化
2.静态工厂方式
3.实例工厂方式
4.实现FactoryBean接口实例化:实例工厂变种:集成其他框架使用
2.构造器方式创建
VO类
public class SomeBean {
public SomeBean(){
System.out.println("SomeBean 被初始化 ....");
}
}
---------------------------------------------------------
beans.xml
<bean id="someBean" class="cn.bdqn.vo.SomeBean" />
---------------------------------------------------------
测试类
public class Tester {
@Test
public void testSpring1() throws Exception {
ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
SomeBean bean = ac.getBean("someBean",SomeBean.class);
System.out.println(bean);
}
}
注意:构造函数的访问权限可以是private私有的。
3.静态工厂方式
VO类
public class SomeBean {
public SomeBean(){
System.out.println("SomeBean 被初始化 ....");
}
}
beans.xml
<bean id="someBean" class="cn.bdqn.vo.SomeBeanFactory" factory-method="createSomeBean"/>
工厂类
public static SomeBean createSomeBean(){
return new SomeBean();
}
测试类
@Test
public void testSpring1() throws Exception {
ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
SomeBean bean = ac.getBean("someBean",SomeBean.class);
System.out.println(bean);
}
3.实例工厂方式
对于工厂类只需要把static去掉。
<bean id="factory" class="cn.bdqn.vo.SomeBeanFactory"/>
<bean id="someBean" factory-bean="factory" factory-method="createSomeBean"/>
4.实现FactoryBean接口实例化
对于实例工厂方式变化的只有配置和工厂类
public class SomeBeanFactoryBean implements FactoryBean<SomeBean> {
//返回SomeBean对象
@Override
public SomeBean getObject() throws Exception {
return new SomeBean();
}
//返回SomeBean的类型
@Override
public Class<?> getObjectType() {
return SomeBean.class;
}
//是否是单例的
@Override
public boolean isSingleton() {
return true;
}
}
配置更简化
<bean id="someBean" class="cn.bdqn.vo.SomeBeanFactoryBean" />
4.Bean的生命周期
六、Spring的基本配置
1.bean标签
<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">
<!--
id :用于设置bean对象的唯一表示
name :用于配置bean对象的别名。同一个bean对象可以有多个别名
别名支持使用","、空格,"."等多种符号进行分隔。但是不支持
中文符号、!等。
class :用于设置Beans的类型(类型 = 包名 + 类名)
-->
<!-- <bean name="user.u1,u2" class="cn.bdqn.vo.User"> -->
<bean id="user" class="cn.bdqn.vo.User">
<!--
配置对象的依赖属性
name :用于指定依赖属性的名称。设置的值为set方法的名称
value :用于设置对象的属性的值
-->
<property name="account" value="Mike"></property>
</bean>
</beans>
2.alias标签
<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="user" class="cn.bdqn.vo.User">
<property name="account" value="Mike"></property>
</bean>
<alias name="user" alias="u1"></alias>
</beans>
3.import标签
<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配置文件
resource :设置引入的资源文件
如果资源文件在指定的包中进行定义的则包的各级之间
需要使用"/"进行分隔("/"表示路径)
使用import标签可以更好的实现团队协作及多人开发
-->
<import resource="config/spring/users.xml"/>
</beans>
七、依赖注入(DI)
1.概述
依赖注入——Dependency Injection。简称为DI。依赖注入只不过是控制反转(IOC)的另一种说法而已。同一个事物只是站在不同的角度上看。
依赖:bean对象的创建依赖于容器,bean的执行依赖于资源
注入:通过容器为对象设置或装配资源
2.如何注入值
方式一:属性注入,通过setter方法
方式二:构造器注入,通过构造器
3.注入的方式
手动装配
基于xml
基于注解自动装配:不安全,不推荐。
4.注入哪些类型的值
1.setter方式
1.简单类型:基本类型+String+URL等
private String name;
private int age;
private double salary;
private URL url;
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public void setSalary(double salary) {
this.salary = salary;
}
public void setUrl(URL url) {
this.url = url;
}
<bean id="employee" class="cn.bdqn.vo.Employee">
<property name="name" value="Mike"></property>
<property name="age" value="20"></property>
<property name="salary" value="10000"></property>
<property name="url" value="http://www.baidu.com"></property>
</bean>
ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
Employee e = ac.getBean("employee",Employee.class);
System.out.println(e);
2.复合类型
public class EmployeeDao {
public void save(){
System.out.println("Dao save is do ......");
}
}
public class EmployeeService {
private EmployeeDao dao;
public void save(){
dao.save();
System.out.println("service save is do....");
}
public void setDao(EmployeeDao dao) {
this.dao = dao;
}
}
<bean id="employeeDao" class="cn.bdqn.vo.EmployeeDao" />
<bean id="employeeService" class="cn.bdqn.vo.EmployeeService">
<property name="dao" ref="employeeDao"></property>
</bean>
@Test
public void testSpring1() throws Exception {
ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
EmployeeService service = ac.getBean("employeeService",EmployeeService.class);
service.save();
}
有时候,若想只有一个bean引用另一个bean。
<bean id="employeeService" class="cn.bdqn.vo.EmployeeService">
<property name="dao">
<bean class="cn.bdqn.vo.EmployeeDao" />
</property>
</bean>
3.集合类型
private Set<String> set;
private List<String> list;
private String[] array;
private Map<String,String> map;
private Properties prop;
public void setSet(Set<String> set) {
this.set = set;
}
public void setList(List<String> list) {
this.list = list;
}
public void setArray(String[] array) {
this.array = array;
}
public void setMap(Map<String, String> map) {
this.map = map;
}
public void setProp(Properties prop) {
this.prop = prop;
}
@Override
public String toString() {
return "CollectionBean [set=" + set + ", list=" + list + ", array="
+ Arrays.toString(array) + ", map=" + map + ", prop=" + prop
+ "]";
}
<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="collectionBean" class="cn.bdqn.vo.CollectionBean">
<property name="set">
<set>
<value>set1</value>
<value>set2</value>
<value>set3</value>
</set>
</property>
<property name="list">
<list>
<value>list1</value>
<value>list2</value>
<value>list3</value>
</list>
</property>
<property name="array">
<array>
<value>array1</value>
<value>array2</value>
<value>array3</value>
</array>
</property>
<property name="map">
<map>
<entry key="key1" value="value1" />
<entry key="key2" value="value2" />
<entry key="key3" value="value3" />
</map>
</property>
<property name="prop">
<props>
<prop key="prop1">value1</prop>
<prop key="prop2">value2</prop>
<prop key="prop3">value3</prop>
</props>
</property>
</bean>
</beans>
以上都是通过setter方式对各种类型的注入
2.构造器方式
简单类型
public class Employee {
private String name;
private int age;
private double salary;
private URL url;
public Employee(String name, int age, double salary, URL url) {
this.name = name;
this.age = age;
this.salary = salary;
this.url = url;
}
@Override
public String toString() {
return "Employee [name=" + name + ", age=" + age + ", salary=" + salary
+ ", url=" + url + "]";
}
}
<bean id="employee" class="cn.bdqn.vo.Employee">
<constructor-arg name="name" value="Rose"></constructor-arg>
<constructor-arg name="age" value="20"></constructor-arg>
<constructor-arg name="salary" value="20000"></constructor-arg>
<constructor-arg name="url" value="http://www.baidu.com"></constructor-arg>
</bean>
对于
<constructor-arg index="" name="" ref="" type="" value="" />
的参数index : 表示第几个参数
type : 参数的类型
name : 参数的名称
value : 参数的简单类型值
ref : 参数的复合类型值复合类型
public class EmployeeService {
private EmployeeDao dao;
public void save(){
dao.save();
System.out.println("service save is do....");
}
public EmployeeService(EmployeeDao dao) {
this.dao = dao;
}
}
<bean id="employeeDao" class="cn.bdqn.vo.EmployeeDao"></bean>
<bean id="employeeService" class="cn.bdqn.vo.EmployeeService">
<constructor-arg name="dao" ref="employeeDao" />
</bean>
对于集合类型构造器的注入只需要把property标签改成
<constructor-arg />
其次还要添加构造器。
七、Bean的继承
abstract public class baseDao {
private String con;
public void update(String sql,Object...params){
System.out.println(con);
System.out.println("sql :"+sql);
}
public void setCon(String con) {
this.con = con;
}
}
public class EmployeeDao extends baseDao {
public void save(){
super.update("INSERT INTO employee.....");
}
}
<bean id="baseDao" class="cn.bdqn.beanextends.baseDao">
<property name="con" value="数据库连接中。。。。" />
</bean>
<bean id="employeeDao" class="cn.bdqn.beanextends.EmployeeDao">
</bean>
以上我们会发现会报错,那是当然的,因为我们的baseDao是抽象类是无法实例化的,配置了bean是肯定会出错的,但是我们去掉abstract运行发现并没有向con中注入到值。
Spring的继承: 是对象之间的继承,bean标签之间的继承
解决:
<bean id="baseDao" abstract="true">
<property name="con" value="数据库连接中。。。。"></property>
</bean>
<bean id="employeeDao" class="cn.bdqn.beanextends.EmployeeDao" parent="baseDao">
</bean>
既然设置了abstract=true在定义class是没有任何意义的,因为已经制定是抽象的,是不能够实例化的了。
当然,我们还可以特定了类中修改注入的值
<bean id="baseDao" abstract="true">
<property name="con" value="数据库连接中。。。。"></property>
</bean>
<bean id="employeeDao" class="cn.bdqn.beanextends.EmployeeDao" parent="baseDao">
<property name="con" value="数据库连接中!!!!!!!"></property>
</bean>
应用:
当多个
<bean/>
有共同的属性配置,那么可以把共同的属性配置放到父<bean>
中去( 设置成abstract的)
八、String的测试
依赖:spring-test-4.3.3.RELEASE.jar
在4.3.3版本中需要Junit4.12或者更高的版本
@RunWith(SpringJUnit4ClassRunner.class):表示先启动Spring容器,把junit运行在Spring容器中
@ContextConfiguration(“”):表示从哪里加载资源文件
若:把@ContextConfiguration(“classpath:applicationContext.xml”) 写成@ContextConfiguration
默认去找的当前测试类名-context.xml配置文件,如:HelloWorldTest-context.xml
测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class Tester {
@Autowired //表示自动装配
private ApplicationContext ac;
@Test
public void test(){
SomeBean bean = ac.getBean("someBean",SomeBean.class);
System.out.println(bean);
}
}