目录
Spring笔记01 1.Spring介绍 1.1 Spring概述1.2 Spring好处1.3 Spring结构体系1.4 在项目中的架构1.5 程序的耦合和解耦2. Spring快速入门 2.1 编写流程2.2 下载地址2.3 Spring的核心jar包2.4 Spring入门案例3. Spring基于XML的IOC细节 3.1 IOC中bean标签和管理对象细节3.2 加载Spring容器的三种方式3.3 BeanFactory和ApplicationContext对比3. 4 Spring的依赖注入DI4. 使用案例Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson 在其著作Expert One-On-One J2EE Development and Design中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。简单来说,Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。
Spring框架是一个分层架构,它包含一系列的功能要素并被分为大约20个模块。这些模块分为Core Container、DataAccess/Integration、Web、AOP、Instrumentation和测试部分。如下图所示:
web层:Struts,SpringMVC
dao层:Hibernate,Mybatis
程序的耦合
我们开发种,会写很多的类,而有些类之间不可避免地产生依赖关系,这种依赖关系称为耦合。有些依赖是必须的,有些依赖关系可以通过优化代码来解除。比如:
/** * 客户的业务层实现类 */ public class CustomerServiceImpl implements ICustomerService { private ICustomerDao customerDao = new CustomerDaoImpl(); }上面的代码表示:业务调用持久层,并且此时业务再依赖持久层的接口和实现类。如果此时没有持久层实现类,编译将不能通过。这种依赖关系就是我们可以通过优化代码解决的。
再比如:下面的代码种,我们的类依赖MySQL的具体驱动类,如果这狮虎更换了数据库品牌,我们需要改源码来修修改数据库驱动,这显然不是我们想要的。
public class JdbcDemo1 { /** * JDBC操作数据库的基本入门中存在什么问题? * 导致驱动注册两次是个问题,但不是严重的。 * 严重的问题:是当前类和mysql的驱动类有很强的依赖关系。 * 当我们没有驱动类的时候,连编译都不让。 * 那这种依赖关系,就叫做程序的耦合 * * 我们在开发中,理想的状态应该是: * 我们应该尽力达到的:编译时不依赖,运行时才依赖。 * * @param args * @throws Exception */ public static void main(String[] args) throws Exception { //1.注册驱动 //DriverManager.registerDriver(new com.mysql.jdbc.Driver()); Class.forName("com.mysql.jdbc.Driver"); //2.获取连接 //3.获取预处理sql语句对象 //4.获取结果集 //5.遍历结果集 }解决程序耦合的思路
在JDBC种是通过反射来注册驱动的,代码如下:Clas.forName("com.mysql.jdbc.Driver"); 这时的好处是,我们类中不再依赖具体的驱动类,此时就算删除MySQL的驱动jar包,依然可以编译。但是没有驱动类,所以不能运行。不过,此处也有一个问题,就是我们反射类对象的全限定类名字符串是在Java类中写死的,一旦要改还是徐娅修改源码。为了解决这个问题,使用配置文件配置。工厂模式解耦
在实际开发过程总我们把所有的dao和service和action对象使用配置文件配置起来,当启动服务器应用加载的时候,通过读取配置文件,把这些对象创建出来并存起来。在接下来使用的时候,直接拿就好了。控制反转---Inversion Of Control
上面解耦的思路有两个问题
创建的对象存储在哪里?由于我们是很多对象,肯定要找个集合来存储,这时候有Map和List供选择。到底是选择Map还是List就看我们有没有查找的需求。有查找的需求就选Map。所以我们的答案是:在应用加载时,创建一个Map,用于存放action,service和dao对象。
还是没解释什么是工厂?工厂就是负责给我们从容器中获取指定对象的类。这时候获取对象的方式发生了改变。以前,我们在获取对象的时候,都是采用new的方式,是主动的。
现在,我么获取对象的时候,同时跟工厂要,有工厂为我们查找或者创建对象。是被动的。这种被动接收的方式获取对象的思想就是控制反转,他是Spring框架的核心之一。其作用只有一个:降低计算机程序的耦合。这里下载4.2.4版本
地址:<http://repo.spring.io/release/org/springframework/spring/4.2.4.RELEASE//>
官网:spring.io 官网改版后,下载链接需要在对应的GitHub上找
spring-core-4.2.4.RELEASE.jar包含Spring框架基本的核心工具类,Spring其他组件都要使用到这个包里得嘞,是其他组件的基本核心。
spring-beans-4.2.4.RELEASE.jar所有应用都要用到的,它包含访问配置文件、创建和管理bean
以及进行Inversion of Control(IoC) / Dependency Injection(DI)操作相关的所有类。
spring-context-4.2.4.RELEASE.jarSpring提供在基础IoC功能上的扩展服务,此外还提供许多企业级服务的支持,
如邮件服务、任务调度、JNDI定位、EJB集成、远程访问、缓存以及各种视图层框架的封装等。
spring-expression-4.2.4.RELEASE.jarSpring表达式语言。
com.springsource.org.apache.commons.logging-1.1.1.jar第三方的主要用于处理日志。
准备项目需要得jar包
spring-framework-4.2.4.RELEASE-dist.zip 【Spring的核心包】spring-framework-4.2.4.RELEASE-dependencies.zip 【Spring的依赖包】创建Project,导入Spring的jar包
在src路径下创建applicationContext.xml文件
导入约束
把资源交给Spring管理,在xml文件中配置User
<?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-framework-4.2.4.RELEASE\docs\spring-framework-reference\html\xsd-configuration.html 文档末尾 --> <!-- 1. 基本配置: bean标签:指定要创建的实体类 id属性:可以为任意值 但是在整个配置文件中唯一 class属性:要实例化类的全限定名 反射 --> <bean id="user" class="com.itzhouq.domain.User"></bean> </beans>测试
package com.itzhouq.domain; public class User { public void run() { System.out.println("run"); } } package com.itzhouq.test; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.itzhouq.domain.User; public class UserTeset { @Test public void test() {//自己new的对象 User user = new User(); user.run(); } @Test public void test2() {//spring的ioc创建对象 //加载配置文件 src/classes类路径 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); //找Spring要对象 User user = (User) context.getBean("user"); user.run(); } }singleton: 单实例 默认值
如果是单实例,配置文件文件只要一加载 就会创建对象 放在spring容器 (map<id,对象>)当所有人过来问spring容器要的时候(getBean),所用人用的都是同一个对象
prototype: 多实例 如果是多实例,配置文件加载,不创建对象当每个人过来getbean的时候,getbean一次创建一次 放在容器中什么时候用默认值singleton(单实例)? 什么时候用prototype(多实例)? action: prototypeservice/dao: singletonrequest:web项目中Spring创建一个Bean对象,将对象存入到request域中session:web项目中Spring创建一个Bean对象,将对象存入到session域中。globalSession:web项目中,应用在Portlet环境,如果没有Portlet环境那么globalSession相当于session。
无参构造方式(最常用)
@Test//测试bean的三种创建方式------无参构造方式 public void test3() { //加载配置文件 src/classes类路径 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); //找Spring要对象 User user = (User) context.getBean("user"); user.run(); }静态工厂方式(了解)
条件:需要有一个工厂类,在这个工厂类中还需要一个静态方法
package com.itzhouq.utils; import com.itzhouq.domain.User; public class BeanFactory { public static User createUser() { return new User(); } } <!-- 静态工厂方式 --> <bean id="user" class="com.itzhouq.utils.BeanFactory" factory-method ="createUser">测试
@Test//测试bean的三种创建方式------静态工厂方式 public void test4() { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); User user1 = (User) context.getBean("user"); System.out.println(user1);//com.itzhouq.domain.User@5f3a4b84 User user2 = (User) context.getBean("user"); System.out.println(user2);//com.itzhouq.domain.User@5f3a4b84 }实例工厂方式(了解)
条件:需要一个工厂类在这个工厂类中需要一个普通方法package com.itzhouq.utils; import com.itzhouq.domain.User; public class BeanFactory { // public static User createUser() { // return new User(); // } //普通方法----实例工厂 public User createUser() { return new User(); } }配置文件
<!-- 实例工厂 --> <bean id="beanFactory" class="com.itzhouq.utils.BeanFactory"></bean> <bean id="user" factory-bean="beanFactory" factory-method="createUser"></bean>测试
@Test//测试bean的三种创建方式------实例工厂方式 public void test5() { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); User user1 = (User) context.getBean("user"); System.out.println(user1);//com.itzhouq.domain.User@5f3a4b84 User user2 = (User) context.getBean("user"); System.out.println(user2);//com.itzhouq.domain.User@5f3a4b84 }类路径获得配置文件
文件系统路径获得配置文件
使用BeanFactory(了解)
public class Lession01 { @Test public void test01(){ //Spring容器加载有3种方式 //第一种:ClassPathXmlApplicationContext ClassPath类路径加载:指的就是classes路径 //最常用,Spring的配置文件以后就放在src路径下 ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); //第二种方式:文件系统路径获得配置文件【绝对路径】 ApplicationContext context = new FileSystemXmlApplicationContext("E:\\workspaces\\IdeaProject\\Spring-day02-gyf\\src\\beans.xml"); IUserService user = (IUserService) context.getBean("userService"); user.add(); //第三种方式: String path = "E:\\workspaces\\IdeaProject\\Spring-day02-gyf\\src\\beans.xml"; BeanFactory factory = new XmlBeanFactory(new FileSystemResource(path)); IUserService user1 = (IUserService) factory.getBean("userService"); user1.add(); } }Spring内部创建对象的原理
1. 解析xml文件,获得类名,id,属性 2. 通过反射,用类型创建对象 3. 给创建的对象赋值DI属性的依赖注入,是Spring框架核心IoC的具体实现方式。Spring在通过Ioc创建对象的时候,如果这个对象还有属性,就一并赋值进去,而不用我们自己去获取。
入门举例:
创建一个接口Car
package com.itzhouq.service; public interface Car { public void run(); }创建实现类CarImpl
package com.itzhouq.serviceImpl; import com.itzhouq.service.Car; public class CarImpl implements Car { private String name; public void setName(String name) { this.name = name; } @Override public void run() { System.out.println(name+"车跑起来了....."); } }测试
package com.itzhouq.test; import org.junit.Test; import com.itzhouq.serviceImpl.CarImpl; public class CarTest { @Test//自己new对象 自己属性赋值的方式 public void test() { CarImpl car = new CarImpl(); car.setName("qq"); car.run();//qq车跑起来了..... } }入门举例2:依赖注入的方式
配置文件:
<!-- DI:属性的依赖注入 --> <bean id="car" class="com.itzhouq.serviceImpl.CarImpl"> <!-- property:是set属性的方式 name:要赋值的属性名 value:要赋的值 --> <property name="name" value="兰博基尼"></property> </bean>测试
@Test //Spring的IOC public void test2() { ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml"); Car car = (Car)context.getBean("car"); //把这个对象的属性也在创建的时候给顺便赋值了-----DI car.run();//兰博基尼车跑起来了..... }依赖注入的方式
构造函数注入(了解)set方法注入(掌握)使用p名称空间注入数据(本质还是调用set方法)(了解)注入集合属性条件:需要有有参构造方法
给CarImpl设置有参构造
package com.itzhouq.serviceImpl; import com.itzhouq.service.Car; public class CarImpl implements Car { private String name; private double price; public void setName(String name) { this.name = name; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } public String getName() { return name; } public CarImpl() {} //有参的构造方法----DI的构造器注入方式 public CarImpl(String name, double price) { super(); this.name = name; this.price = price; } @Override public void run() { System.out.println("价值"+price+"的"+name+"车跑起来了....."); } }配置文件
<!-- DI的注入方式,构造器注入方式 name:要赋值的属性名 value:要赋的值(针对的是基本数据类型和String类型) ref针对的是对象类型 --> <bean id="car" class="com.itzhouq.serviceImpl.CarImpl"> <constructor-arg name="name" value="BMW"></constructor-arg> <constructor-arg name="price" value="1000000"></constructor-arg> </bean>测试
@Test //Spring的DI注入方式----构造器的注入方式(了解) public void test3() { ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml"); Car car = (Car)context.getBean("car"); car.run();//价值1000000.0的BMW车跑起来了..... }写一个Person接口
package com.itzhouq.service; public interface Person { }PersonImpl实现接口Person,设置set方法
package com.itzhouq.serviceImpl; import com.itzhouq.service.Car; import com.itzhouq.service.Person; public class PersonImpl implements Person { private String name; private Car car; public String getName() { return name; } public void setName(String name) { this.name = name; } public Car getCar() { return car; } public void setCar(Car car) { this.car = car; } @Override public String toString() { return "PersonImpl [name=" + name + ", car=" + car + "]"; } }配置文件
<bean id="car" class="com.itzhouq.serviceImpl.CarImpl"> <constructor-arg name="name" value="BMW"></constructor-arg> <constructor-arg name="price" value="1000000"></constructor-arg> </bean> <!-- DI的注入方式,set注入方式 name:要赋值的属性名 value:要赋的值(针对的是基本数据类型和String类型) ref针对的是对象类型,指的是Spring中bean的id名 --> <bean id="person" class="com.itzhouq.serviceImpl.PersonImpl"> <property name="name" value="jack"></property> <property name="car" ref="car"></property> </bean>测试
@Test //Spring的DI注入方式----set的注入方式(了解) public void test4() { ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml"); Person person = (Person) context.getBean("person"); System.out.println(person); //PersonImpl [name=jack, car=CarImpl [name=BMW, price=1000000.0]] }此种方式是通过在xml中导入p名称空间,使用p:propertyName来注入数据,它的本质仍然是调用类中的set方法实现注入功能。
配置文件
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" 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="customerService" class="com.itheima.service.impl.CustomerServiceImpl4" p:name="test" p:age="21" p:birthday-ref="now"/> </beans>顾名思义,就是给类中的集合成员传值,它用的也是set方法注入的方式,只不过变量的数据类型都是集合。我们这里介绍注入数组,List,Set,Map,Properties。
创建一个类CollBean,设置set方法
package com.itzhouq.domain; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Properties; public class CollBean { private String[] ss; private List ll; private Map mm; private Properties properties; public String[] getSs() { return ss; } public void setSs(String[] ss) { this.ss = ss; } public List getLl() { return ll; } public void setLl(List ll) { this.ll = ll; } public Map getMm() { return mm; } public void setMm(Map mm) { this.mm = mm; } public Properties getProperties() { return properties; } public void setProperties(Properties properties) { this.properties = properties; } @Override public String toString() { return "CollBean [ss=" + Arrays.toString(ss) + ", ll=" + ll + ", mm=" + mm + ", properties=" + properties + "]"; } }配置文件
<bean id="car" class="com.itzhouq.serviceImpl.CarImpl"> <constructor-arg name="name" value="BMW"></constructor-arg> <constructor-arg name="price" value="1000000"></constructor-arg> </bean> <!-- DI复杂属性注入 --> <bean id="collBean" class="com.itzhouq.domain.CollBean"> <property name="ss"> <!-- 数组类型 --> <list> <value>aaa</value> <value>bbb</value> <value>ccc</value> </list> </property> <property name="ll"> <!-- 集合类型 --> <list> <value>111</value> <value>222</value> <ref bean="car"></ref> </list> </property> <property name="mm"> <!-- map类型 --> <map> <entry key="k1" value="AAA"></entry> <entry key="k2" value="BBB"></entry> <entry key="k3" value-ref="car"></entry> </map> </property> <property name="properties"> <!-- properties --> <props> <prop key="hibernate.username">root</prop> <prop key="hibernate.password">1234</prop> </props> </property> </bean>测试
package com.itzhouq.test; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.itzhouq.domain.CollBean; public class CollBeanTest { @Test public void test() { ApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml"); CollBean cb = (CollBean) context.getBean("collBean"); System.out.println(cb); /* * CollBean [ss=[aaa, bbb, ccc], * ll=[111, 222, CarImpl [name=BMW, price=1000000.0]], * mm={k1=AAA, k2=BBB, k3=CarImpl [name=BMW, price=1000000.0]}, * properties={hibernate.password=1234, hibernate.username=root}] */ } }需求分析:从service层调用dao层,将数据存储到数据库,存储数据的过程使用syso模拟一下就可以。
创建工程,导入需要的jar包,建包如下:
创建dao层和dao实现层
package com.itzhouq.dao; public interface UserDao { void save(); } package com.itzhouq.daoImpl; import com.itzhouq.dao.UserDao; public class UserDaoImpl implements UserDao{ @Override public void save() { System.out.println("操作数据库,保存用户的数据"); } }创建Service层和实现层
package com.itzhouq.service; public interface UserService { public void save(); } package com.itzhouq.serviceImpl; import com.itzhouq.dao.UserDao; import com.itzhouq.daoImpl.UserDaoImpl; import com.itzhouq.service.UserService; public class UserServiceImpl implements UserService { private String name; private UserDao userDao; public void setUserDao(UserDao userDao) { this.userDao = userDao; } public void setName(String name) { this.name = name; } @Override public void save() { System.out.println(name); //调用dao userDao.save(); } } 给UserDaoImpl一个UserDao属性配置文件
<?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"> <!-- 创建dao --> <bean id="userDao" class="com.itzhouq.daoImpl.UserDaoImpl"></bean> <!-- 创建service --> <bean id="UserService" class="com.itzhouq.serviceImpl.UserServiceImpl"> <property name="name" value="要开始访问dao了"></property> <property name="userDao" ref="userDao"></property> </bean> </beans>测试
@Test //使用Spring的IOC+DI来实现对象的创建和赋值 public void test() { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); UserService userService = (UserService) context.getBean("UserService"); userService.save(); //要开始访问dao了 //操作数据库,保存用户的数据 }转载于:https://www.cnblogs.com/itzhouq/p/spring01.html