控制的什么被反转了?就是获得依赖对象的方式被反转了——Martin Fowler
1、Spring基本知识
1.1 什么是Spring?
- Spring是分层JavaSE/EE full-stack轻量级开源框架
- 以IoC(Inverse of Control,控制反转)和AOP(Aspect Oriented Programing,面向切面编程)为核心
- 实际开发中,通常采用三层体系架构(web、service、dao)。spring对每一层都提供了技术支持,在表示层提供了与struts2框架的整合,在业务逻辑层可以管理事务、记录日志等,在持久层可以整合Hibernate、JdbcTemplate等技术
1.2 Spring框架的优点
- 方便解耦,简化开发 (高内聚低耦合) Spring就是一个大工厂(容器),可以将所有对象创建和依赖关系维护,交给Spring管理spring工厂是用于生成bean
- AOP编程的支持 Spring提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能
- 声明式事务的支持 只需要通过配置就可以完成对事务的管理,而无需手动编程
- 方便程序的测试 Spring对Junit4支持,可以通过注解方便的测试Spring程序
- 方便集成各种优秀框架 Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如:Struts、Hibernate、MyBatis、Quartz等)的直接支持
- 降低JavaEE API的使用难度 Spring 对JavaEE开发中非常难用的一些API(JDBC、JavaMail、远程调用等),都提供了封装,使这些API应用难度大大降低
1.3 Spring的体系结构
核心容器:beans、core、context、expression
1.4 Spring的下载及目录结构
下载地址:http://repo.spring.io/simple/libs-release-local/org/springframework/spring/3.2.0.RELEASE
目录结构:
libs中有50多个jar文件,有4个Spring的基础包,分别对应Spring核心容器的4个模块
spring-core-3.2.0.RELEASE.jar 包含Spring框架基本的核心工具类,Spring其他组件都要用到这个包里的类,是其他组件的基本核心
spring-beans-3.2.0.RELEASE.jar 所有应用都要用到的,它包含访问配置文件、创建和管理bean以及进行IoC或者DI操作相关的类
spring-context-3.2.0.RELEASE.jar 在基础IoC功能上的扩展服务
spring-expression-3.2.0.RELEASE.jar 定义了Spring的表达式语言
2. 入门案例:IoC
2.1 导入jar包 4核心+1依赖
2.2 目标类
UserDao接口
public interface UserDao { public void addUser(); }
UserDaoImpl实现类
public class UserDaoImpl implements UserDao { @Override public void addUser() { System.out.println("添加用户"); } }
2.3 配置文件
spring帮我们创建对象,但也必须有相关类的信息,不然怎么能够创建呢?
配置文件名称:建议:ApplicationContext.xml,取别的也可以,但是取建议的名称的话,找到该配置文件更为简单,
配置文件位置:任意,一般都在classpath下(src)
文件约束内容:添加约束,spring-framework-3.2.0.RELEASE 为spring的核心 docs为帮助文档
约束位置:spring-framework-3.2.0.RELEASEdocsspring-framework-referencehtmlxsd-config.html
<?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="userDao" class="com.tcxpz.spring_chapter01.ioc.UserDaoImpl"></bean>
</beans>
2.4 测试
public class TestIoC {
@Test
public void demo(){
/*
* 以前的做法是 UserDao userDao = new UserDaoImpl()
* 现在交给Spring来创建,程序从Spring容器中获取
*/
//1 定义配置文件的路径(项目中一般放在src目录下,此处为方便放在包下)
String xmlPath = "com/tcxpz/spring_chapter01/ioc/applicationContext.xml";
//2 初始化Spring容器,加载配置文件
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
//3 通过容器获取userDao实例
UserDao userDao = (UserDao) applicationContext.getBean("userDao");
//调用userDao的addUser()方法
userDao.addUser();
}
}
测试结果:
3 入门案例2:DI
依赖注入(DI):spring创建对象A时,会将对象A所依赖的对象B也创建出来,并自动注入到对象A中。
依赖:(has a) 有一个的意思,比如类A中有一个类B,那么就说A依赖B。
继承,实现:(is a)
当出现一个类依赖于另一个类时,之前的开发是这样的
public class UserServiceImpl implements UserService { private UserDao userDao = new UserDaoImpl(); @Override public void save() { userDao.addUser(); } }
学习了Spring之后,开发就是这样的了
public class UserServiceImpl implements UserService { private UserDao userDao; public void setUserDao(UserDao userDao) { this.userDao = userDao; } @Override public void save() { userDao.addUser(); } }
3.1 导入jar包(同2.1)
3.2 目标类
UserDao接口与UserDaoImp实现类(同2.2)
UserService接口与UserServiceImpl实现类
public interface UserService { public void save(); }
public class UserServiceImpl implements UserService { private UserDao userDao; public void setUserDao(UserDao userDao) { this.userDao = userDao; } @Override public void save() { userDao.addUser(); } }
3.3 配置文件
<?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"> <!-- 创建UserDao对象 --> <bean id="userDao" class="com.tcxpz.spring_chapter01.di.UserDaoImpl"></bean> <!-- 创建Service对象 --> <bean id="userService" class="com.tcxpz.spring_chapter01.di.UserServiceImpl"> <!-- <property> 用于进行属性注入 name: bean的属性名,通过setter方法获得 setBookDao ##> BookDao ##> bookDao ref :依赖的另一个bean的id值的引用 --> <property name="userDao" ref="userDao"></property> </bean> </beans>
3.4 测试
public class TestDI { @Test public void demo(){ String xmlPath = "com/tcxpz/spring_chapter01/di/applicationContext.xml"; ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath); UserService userService = (UserService) applicationContext.getBean("userService"); userService.save(); } }
测试结果
4 Spring中的bean
4.1 Bean的配置
可以把Spring看做一个大型的工厂,而Spring容器中的bean就是该工厂的产品
Spring容器支持两种格式的文件,分别为Properties文件格式和XML文件格式,在实际开发中,最常用的是XML文件格式的配置方式
每一个<bean>子元素定义了一个bean,并且描述了该bean如何被装配到Spring容器中。<bean>中包含很多属性:id,name,class,scope,constructor-arg,property,ref,value,list,set,map,entry
4.2 Bean的实例化
并不是每个bean都是普通类,有些是通过工厂来获取的,而工厂就有静态工厂和实例工厂,所以spring创建实例对象有三种情况,
默认无参构造:直接<bean id="" class="">,必须提供无参的构造方法
静态工厂:由于是静态工厂,所以通过工厂类直接调用创建实例的静态方法就可以了,不需要创建工厂的实例对象。
<bean id="" class="工厂全限定类名" factory-method="静态方法">
实例工厂:需要先创建出工厂实例对象,然后再由工厂实例对象的方法创建对象,所以会有两个Bean
<bean id="myFactoryId" class="工厂全限定类名"></bean>
<bean id="" factory-bean="myFactoryId" factory-method=""></bean>
4.3 Bean的作用域
作用域的种类:singleton prototype request session global
主要掌握前两个即可
单例模式(singleton):使用singleton定义的Bean在Spring容器中只有一个实例,也就是说,无论有多少个Bean引用它,始终指向同一个对象(默认作用域)
public class TestDI { @Test public void demo(){ String xmlPath = "com/tcxpz/spring_chapter01/di/applicationContext.xml"; ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath); UserService userService1 = (UserService) applicationContext.getBean("userService"); UserService userService2 = (UserService) applicationContext.getBean("userService"); System.out.println(userService1==userService2); } }
原型模式(prototype):每次通过Spring容器获取的prototype定义的Bean时,容器都将创建一个新的实例。
4.4 Bean的生命周期
Spring容器可以管理singleton作用域下Bean的生命周期,再次作用于下,Spring能够精确地知道该何时创建,何时初始化完成,以及何时被销毁。
而对于prototype作用域的Bean,Spring只负责创建,当容器创建了Bean实例后,Bean的实例就交给客户端代码来管,Spring容器就不再跟踪其生命周期。
4.5 Bean的装配方式
Bean的装配可以理解为依赖关系注入,Bean的装配方式也就是Bean依赖注入的方式。主要有三种:基于XML 基于注解 自动装配
4.5.1 基于XML的装配
主要有两种方式:setter注入和构造注入 setter注入时,Bean类必须提供一个默认的构造方法,而且必须为注入的属性提供setter方法
(1)导包 4核心+1依赖
(2)创建User类
public class User { private String username; private Integer password; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public Integer getPassword() { return password; } public void setPassword(Integer password) { this.password = password; } //默认构造 public User(){ } //构造方法注入 public User(String username,Integer password){ super(); this.username=username; this.password=password; } @Override public String toString() { return "User [username=" + username + ", password=" + password + "]"; } }
(3)测试
public class TestUser { @Test public void demo(){ String xmlPath="com/tcxpz/spring_chapter01/domain/applicationContext.xml"; ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath); User user1 = (User) applicationContext.getBean("user1"); User user2 = (User) applicationContext.getBean("user2"); System.out.println(user1); System.out.println(user2); } }
不管是普通属性还是引用数据,都可以通过构造方法进行注入。通过setter方法进行注入引用数据。
通过setter方法对普通属性和引用属性进行注入,那么要是创建的对象中有集合呢?那该如何进入注入?
集合的注入List、Map、Set、数组、Properties等。
list
set
map
数组:
properties
注意:集合之间可以相互嵌套,比如list中可能装有对象(bean)等等
4.5.2 基于Annotation的装配
注解格式:@xxx 开发中通常采用注解取代xml配置文件
使用注解:必须对使用注解的地方进行扫描,不然注解没用。而扫描需要做两件事
1、添加名称空间
在我们找配置文件中约束的位置那:spring-framework-3.2.0.RELEASEdocsspring-framework-referencehtmlxsd-config.html 找到context的名称空间。
2. 扫描指定的目录
注解:
1、@Component 替代 <bean id="" class=""> 可以配置任意bean,在所在类上面添加该注解即可,
@Component("userId") userId相当于bean中的id属性值
2、这三个就跟使用@Component是一样的,但是为了更好的体现三层架构,就有了这三个注解
@Controller 修饰web层中的类。
@Service 修饰service层的类
@Repository 修饰dao层的类
两种方式,一种不声明名称,一种声明名称
@Controller("xxx") @Controller
如果声明了名称,那么在别的地方引用的话,就可以使用@Autowired或@Autowired与@Qualifier的组合 或直接使用@Resource按照名称注入
如果没有声明名称,那么在别的地方引用的话,只能使用@Autowired 来进行注入
3、属性注入
普通属性
@Value @Value("") 给普通属性注入属性值
引用属性
@Autowired 按默认类型进行注入
@Qualifier("") 按照名称注入
如果使用了@Qualifier这个注解,那么就需要两个一起使用才能生效。如果只使用@Autowired,那么写不写@Qualifier都可以
引用属性
@Resource 直接按照名称注入,与上面两个注解一起使用是等效的
@Resource(name="xxx")
4、使用
5、其他注解
@Scope("prototype") 作用域注解(spring帮我们创建的bean实例的作用域,在下面会讲解到)
@PostConstruct 修饰初始化
@PreDestory 修饰销毁
最后两个用的不多,掌握前面的即可。
4.5.3 P命令空间[了解]
对“setter方法注入”进行简化,替换<property name="属性名">,而是在<bean p:属性名="普通值" p:属性名-ref="引用值">
p命名空间使用前提,必须添加命名空间
<bean id="personId" class="com.itheima.f_xml.c_p.Person" p:pname="jack" p:age="22" p:homeAddr-ref="homeAddrId" p:companyAddr-ref="companyAddrId"> </bean> <bean id="homeAddrId" class="com.itheima.f_xml.c_p.Address" p:addr="北京" p:tel="010"> </bean> <bean id="companyAddrId" class="com.itheima.f_xml.c_p.Address" p:addr="合肥" p:tel="0551"> </bean>
4.5.4 SpEL[了解]
对<property>进行统一编程,所有的内容都使用value
<property name="" value="#{表达式}">
#{123}、#{'jack'} : 数字、字符串
#{beanId} :另一个bean引用
#{beanId.propName} :操作数据
#{beanId.toString()} :执行方法
#{T(类).字段|方法} :静态方法或字段
5 myeclipse schema xml提示
步骤一:确定xsd文件位置:spring-framework-3.2.0.RELEASEschemaeans
步骤二:复制路径
步骤三:搜索“xml catalog”
步骤四:添加约束提示