1.引入
之前一直在用Spring、SpringMVC、MyBatis开发,但是却没有系统学习、整理这三大框架的知识点。从以前的SSH到现在的SSM,SpringMVC取代了Struts2,Mybatis取代了Hibernate,唯一不变的是Spring,正如它的中午含义 — —“春天”一般,它是JAVA程序员的春天,没有它兴许就不会有当下如此兴盛的JAVA时代。而Spring的博大精深,其原理更是非常值得我们去探究的。于是打算写下一系列的Spring博客,梳理一下其中的知识点。
Spring是一个开源框架,Spring是于2003 年兴起的一个轻量级的Java 开发框架,由Rod Johnson 在其著作Expert One-On-One J2EEDevelopment and Design中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 J2EE 应用程序开发提供集成的框架。Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。简单来说,Spring是一个分层的JavaSE/EE full-stack(一站式) 轻量级开源框架。
Spring的核心是控制反转(IoC)和面向切面(AOP)。
2.Spring的优点
Spring有很多优点,主要有一下几点:
-
方便解耦,简化开发 (高内聚低耦合)
Spring就是一个大工厂(容器),可以将所有对象创建和依赖关系维护,交给Spring管理
spring工厂是用于生成bean
-
AOP编程的支持
Spring提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能
-
声明式事务的支持
只需要通过配置就可以完成对事务的管理,而无需手动编程
-
方便程序的测试
Spring对Junit4支持,可以通过注解方便的测试Spring程序
-
方便集成各种优秀框架
Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如:Struts、Hibernate、MyBatis、Quartz等)的直接支持
-
降低JavaEE API的使用难度
Spring 对JavaEE开发中非常难用的一些API(JDBC、JavaMail、远程调用等),都提供了封装,使这些API应用难度大大降低
看完以上,你肯定会有不少的困惑,不要着急,不用担心,接着往下学习,所有的问题都会逐步化解。
3.Spring的体系结构
Spring 框架是一个分层架构,,它包含一系列的功能要素并被分为大约20个模块。这些模块分为Core Container、Data Access/Integration、Web、AOP(Aspect Oriented Programming)、Instrumentation和测试部分,如下图所示:
1.Core Container : 核心容器
Beans : 管理Bean
Core : 核心
Context :上下文(最终都会体现在配置文件)
Expression Language :SpEL表达式
2.AOP : 切面编程
Aspects : AOP框架
3.JDBC : JDBC Template开发
ORM : 整合hibernate
Transactions :事物管理Tx
4.Web : web开发
Struts:整合Struts
5.Test : 整合Junit
核心容器则为:beans、core、context、expression 。
4.Spring环境搭建
搭建Spring环境的第一步,就是导入JAR包。Spring的JAR包永远记住一个原则:
4 + 1 : 4个核心(beans、core、context、expression上文所述的核心容器) + 1个依赖(commons-loggins...jar)
配置文件:
- 位置:任意,开发中一般在classpath下(src)
- 名称:任意,开发中常用applicationContext.xml
- 内容:添加schema约束
- 约束文件位置:spring-framework-3.2.0.RELEASE\docs\spring-framework-reference\html\xsd-config.html
5.IOC控制反转
- 提供UserService接口及其实现类
- 获得UserService实现类实例
如果没有学习过Spring,获取实例直接new一个对象即可,但是现在,我们正在学习Spring,它的神奇之一在于,Spring可以为我们创建对象实例 — —即IoC 控制反转(Inverse of Control)。之后需要实例对象时,从Spring工厂(容器)中获得,需要将实现类的全限定名称配置到xml文件中。
根据一个简单的例子,我们可以入门IOC。
public interface UserService {
public void addUser();
}
public class UserServiceImp implements UserService {
@Override
public void addUser() {
System.out.println("hello Ioc ");
}
}
配置文件
<?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">
<!-- 配置service
<bean> 配置需要创建的对象
id :用于之后从spring容器获得实例时使用的
class :需要创建实例的全限定类名
-->
<bean id="userServiceId" class="com.spring.ioc.UserServiceImp"></bean>
</beans>
测试类:
public class TestIoc {
@Test
public void testBefore() throws Exception {
//学习Spring之前
UserService userService = new UserServiceImp();
userService.addUser();
}
@Test
public void testIoc() throws Exception {
//学习Spring之后
//从Spring容器中获得
//1.获得容器
String xmlPath = "com/spring/ioc/beans.xml";
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
//2.获得内容--不再需要自己去new 都是从spring容器中获得
UserService userService = (UserService) applicationContext.getBean("userServiceId");
userService.addUser();
}
}
6.核心API
-
BeanFactory :这是一个工厂,用于生成任意bean。采取延迟加载,第一次getBean时才会初始化Bean
-
ApplicationContext:是BeanFactory的子接口,功能更强大。(国际化处理、事件传递、Bean自动装配、各种不同应用层的Context实现)。当配置文件被加载,就进行对象实例化。
- ClassPathXmlApplicationContext 用于加载classpath(类路径、src)下的xml
加载xml运行时位置 --> /WEB-INF/classes/...xml
- FileSystemXmlApplicationContext 用于加载指定盘符下的xml
加载xml运行时位置 --> /WEB-INF/...xml
通过java webServletContext.getRealPath() 获得具体盘符
@Test
public void demo02(){
//使用BeanFactory --第一次条用getBean实例化
String xmlPath = "com/<span style="font-family:SimSun;">spring</span>/<span style="font-family:SimSun;">di</span>/beans.xml";
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource(xmlPath));
BookService bookService = (BookService) beanFactory.getBean("bookServiceId");
bookService.addBook();
}
7.装配Bean
7.1基于XML
7.1.1实例化方式
3种bean实例化方式:默认构造、静态工厂、实例工厂
- 默认构造:
<bean id="" class=""> 必须提供默认构造
- 静态工厂:
常用与spring整合其他框架(工具)
静态工厂:用于生成实例对象,所有的方法必须是static
<bean id="" class="工厂全限定类名(<span style="font-family:SimSun;">包名+类名</span>)" factory-method="静态方法">
eg:
工厂类
public class MyBeanFactory {
/**
* 创建实例
* @return
*/
public static UserService createUserService(){
return new UserServiceImp();
}
}
spring配置
<?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">
<!-- 配置service
<bean> 配置需要创建的对象
id :用于之后从spring容器获得实例时使用的
class :需要创建实例的全限定类名
factory-method:调用的静态工厂方法
-->
<bean id="userServiceId" class="com.spring.di.MyBeanFactory" factory-method="createUserService"></bean>
</beans>
测试类:
public class TestStaticFactory {
//学习spring之前
@Test
public void demo01() throws Exception {
UserService userService = MyBeanFactory.createUserService();
userService.addUser();
}
//学习spring之后
@Test
public void demo02() throws Exception {
//spring工厂
String mPath = "com/spring/di/beans.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(mPath);
UserService userService = applicationContext.getBean("userServiceId", UserService.class);
userService.addUser();
}
}
- 实例工厂:
必须先有工厂实例对象,通过实例对象创建对象。提供所有的方法都是“非静态”的。
Spring配置
<?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="myBeanFactoryId" class="com.spring.myFactory.MyBeanFactory" ></bean>
<!-- 获得userService
factory-bean 确定工厂实例
factory-method 确定普通方法
-->
<bean id="userServiceId" factory-bean="myBeanFactoryId" factory-method="createUserService"></bean>
</beans>
测试类
//学习spring之前
@Test
public void demo01() throws Exception {
MyBeanFactory myBeanFactory = new MyBeanFactory();
UserService userService = myBeanFactory.createUserService();
userService.addUser();
}
//学习spring之后
@Test
public void demo02() throws Exception {
//springg工厂
String mPath = "com/spring/myFactory/beans.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(mPath);
UserService userService = applicationContext.getBean("userServiceId", UserService.class);
userService.addUser();
}
7.1.2 Bean的种类
-
普通bean:之前操作的都是普通bean。<beanid="" class="A"> ,spring直接创建A实例,并返回
-
FactoryBean:是一个特殊的bean,具有工厂生成对象能力,只能生成特定的对象。
bean必须使用 FactoryBean接口,此接口提供方法 getObject() 用于获得特定bean。
<beanid="" class="FB"> 先创建FB实例,使用调用getObject()方法,并返回方法的返回值
FB fb = new FB();
returnfb.getObject();
官方文档中的描述:
Interface to be implemented by objects used within a BeanFactory which are themselves factories.
If a bean implements this interface, it is used as a factory for an object to expose,
not directly as a bean instance that will be exposed itself.
NB: A bean that implements this interface cannot be used as a normal bean.
A FactoryBean is defined in a bean style,
but the object exposed for bean references (getObject() is always the object that it creates.
-
BeanFactory 和 FactoryBean 对比?
BeanFactory:工厂,用于生成任意bean。
FactoryBean:特殊bean,用于生成另一个特定的bean。例如:ProxyFactoryBean ,此工厂bean用于生产代理。 <bean id=""class="....ProxyFactoryBean"> 获得代理对象实例。AOP使用
7.1.3作用域
-
作用域:用于确定spring创建bean实例个数
- 取值
类别 | 说明 |
---|---|
singleton | 在Spring IoC容器中仅存在一个Bean实例,Bean以单例方式存在,默认值 |
prototype | 每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时 ,相当于执行new XxxBean() |
request | 每次HTTP请求都会创建一个新的Bean,该作用域仅适用于WebApplicationContext环境 |
session | 同一个HTTP Session 共享一个Bean,不同Session使用不同Bean,仅适用于WebApplicationContext 环境 |
globalSession | 一般用于Portlet应用环境,该作用域仅适用于WebApplicationContext 环境 |
singleton 单例,默认值。
prototype 多例,每执行一次getBean将获得一个实例。例如:struts整合spring,配置action多例。
- 配置信息
<bean id="" class="" scope="">
<bean id="userServiceId" class="com.<span style="font-family:SimSun;">spring</span>.scope.UserServiceImpl" scope="prototype" ></bean>
7.1.4生命周期
- 初始化和销毁
-目标方法执行前后执行后,将进行初始化或销毁。
<bean id="" class="" init-method="初始化方法名称" destroy-method="销毁的方法名称">
示例代码:
public class UserServiceImp implements UserService {
@Override
public void addUser() {
System.out.println("My Lisfe Cycle");
}
public void myInit(){
System.out.println("myInit");
}
public void myDestory(){
System.out.println("myDestory");
}
}
配置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">
<!--
init-method 用于配置初始化方法,准备数据等
destroy-method 用于配置销毁方法,清理资源等
-->
<bean id="userServiceId" class="com.spring.lifeCycle.UserServiceImp"
init-method="myInit" destroy-method="myDestory"></bean>
</beans>
测试类:
@Test
public void testLife() throws Exception {
//学习Spring之后
//从Spring容器中获得
//1.获得容器
String xmlPath = "com/spring/lifeCycle/beans.xml";
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
//2.获得内容--不再需要自己去new 都是从spring容器中获得
UserService userService = (UserService) applicationContext.getBean("userServiceId");
userService.addUser();
//要求:1.容器必须close,销毁方法执行; 2.必须是单例的
// applicationContext.getClass().getMethod("close").invoke(applicationContext);
// * 此方法接口中没有定义,实现类提供
applicationContext.close();
}
执行结果:
2.BeanPostProcessor 后处理Bean
-
spring 提供一种机制,只要实现此接口BeanPostProcessor,并将实现类提供给spring容器,spring容器将自动执行,在初始化方法前执行before(),在初始化方法后执行after() 。 配置<bean class="">
参见Spring官方文档:
-
Factory hook that allows for custom modification of new bean instances, e.g. checking for marker interfaces or wrapping them with proxies.(来源Spring官方文档)
spring提供工厂钩子,用于修改实例对象,可以生成代理对象,是AOP底层。
这并不好理解,我们可以用伪代码模拟一下过程。A a =new A();
a = B.before(a) <span style="font-family:SimSun;">//</span> 将a的实例对象传递给后处理bean,可以生成代理对象并返回。
a.init();
a = B.after(a);
a.addUser(); //生成代理对象,目的在目标方法前后执行(例如:开启事务、提交事务)
a.destroy()
示例代码:
编写实现类
public class MyBeanPostProcessor implements BeanPostProcessor{
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
System.out.println("Before" + beanName);
return bean;
}
@Override
public Object postProcessAfterInitialization(final Object bean, String beanName)
throws BeansException {
System.out.println("After" + beanName);
//Bean目标对象 生成JDK代理
return Proxy.newProxyInstance(MyBeanPostProcessor.class.getClassLoader()
, bean.getClass().getInterfaces()
, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out
.println("开启事物");
//执行目标方法
method.invoke(bean, args);
System.out
.println("提交事物");
//执行目标方法
return null;
}
});
}
}
配置
<bean class="com.spring.lifeCycle.MyBeanPostProcessor"></bean>
结果:
学习完生命周期后,我们必须思考两个问题:
Q1:后处理bean作用某一个目标类,还是所有目标类?
A:所有
Q2:如何只作用一个?
A:通过“参数2”beanName进行控制
7.1.4属性依赖注入
1.依赖注入方式:手动装配 和 自动装配2.手动装配:一般进行配置信息都采用手动
- 基于xml装配:构造方法、setter方法
-
基于注解装配:(详见7.2)
- byType:按类型装配
- byName:按名称装配
- constructor构造装配,
- auto: 不确定装配
7.1.4.1构造方法
<constructor-arg>:用于配置构造方法一个参数argument
name :参数的名称
value:设置普通数据
ref:引用数据,一般是另一个bean id值
index :参数的索引号,从0开始 。如果只有索引,匹配到了多个构造方法时,默认使用第一个。
type :确定参数类型
示例代码:
package com.spring.xml.constructor;
public class User {
private Integer uid;
private String username;
private Integer age;
public User(String username, Integer age) {
super();
this.username = username;
this.age = age;
}
public Integer getUid() {
return uid;
}
public void setUid(Integer uid) {
this.uid = uid;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "User [uid=" + uid + ", username=" + username + ", age=" + age
+ "]";
}
}
配置文件
<?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">
<!-- 构造方法注入
* <constructor-arg> 用于配置构造方法一个参数argument
name :参数的名称
value:设置普通数据
ref:引用数据,一般是另一个bean id值
index :参数的索引号,从0开始 。如果只有索引,匹配到了多个构造方法时,默认使用第一个。
type :确定参数类型
例如:使用名称name
<constructor-arg name="username" value="jack"></constructor-arg>
<constructor-arg name="age" value="18"></constructor-arg>
例如2:【类型type 和 索引 index】
<constructor-arg index="0" type="java.lang.String" value="1"></constructor-arg>
<constructor-arg index="1" type="java.lang.Integer" value="2"></constructor-arg>
-->
<bean class="com.spring.xml.constructor.User" id="userId">
<constructor-arg name="username"></constructor-arg>
<constructor-arg name="age"></constructor-arg>
</bean>
</beans>
测试类:
public class TestUser {
@Test
public void demo01() throws Exception {
String xmlPath = "com/spring/xml/constructor/beans.xml";
ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext(xmlPath);
User bean = classPathXmlApplicationContext.getBean("userId", User.class);
System.out.println(bean);
}
7.1.4.2setter方法
setter方法,本质上就是去寻找该对象的setter方法,把值设置进去,毕竟简单,直接看示例代码就好。
<?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">
<!-- setter方法注入
* 普通数据
<property name="" value="值">
等效
<property name="">
<value>值
* 引用数据
<property name="" ref="另一个bean">
等效
<property name="">
<ref bean="另一个bean"/>
-->
<bean id="personId" class="com.spring.xml.setter.Person">
<property name="pname" value="keo"></property>
<property name="age">
<value>21</value>
</property>
<property name="homeAddr" ref="homeAddrId"></property>
<property name="companyAddr">
<ref bean="companyAddrId"/>
</property>
</bean>
<bean id="homeAddrId" class="com.spring.xml.setter.Address">
<property name="addr" value="beijing"></property>
<property name="tel" value="911"></property>
</bean>
<bean id="companyAddrId" class="com.spring.xml.setter.Address">
<property name="addr" value="北京海淀"></property>
<property name="tel" value="120"></property>
</bean>
</beans>
7.1.4.3.P命令空间
- 对“setter方法注入”进行简化,替换<property name="属性名">,而是在
<beanp:属性名="普通值" p:属性名-ref="引用值">
- p命名空间使用前提,必须添加命名空间
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p ="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
<span style="font-family:SimSun;"> </span>http://www.springframework.org/schema/beans/spring-beans.xsd"
>
示例配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p ="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
<span style="font-family:SimSun;"> </span>http://www.springframework.org/schema/beans/spring-beans.xsd"
>
<bean id="personId" class="com.spring.xml.p.Person"
p:pname="keo" p:age="22"
p:homeAddr-ref="homeAddrId" p:companyAddr-ref="companyAddrId">
</bean>
<bean id="homeAddrId" class="com.spring.xml.p.Address"
p:addr="DG" p:tel="beijing">
</bean>
<bean id="companyAddrId" class="com.spring.xml.p.Address"
p:addr="DG" p:tel="shanghai">
</bean>
</beans>
在真正的开发中,这种方式用的还是比较少的,相对而言,property配置会更多一些。
7.1.4.4SpEL表达式
-
对<property>进行统一编程,所有的内容都使用value
<propertyname="" value="#{表达式}">
#{123}、#{'jack'} : 数字、字符串
#{beanId} :另一个bean引用
#{beanId.propName} :操作数据
#{beanId.toString()} :执行方法
#{T(类).字段|方法}:静态方法或字段
...
这种方法,用的比较少,所以了解一下即可。有兴趣的朋友可以再去深入了解。
示例代码
<span style="font-family:SimSun;font-size:14px;"><!--
<property name="cname" value="#{'jack'}"></property>
<property name="cname" value="#{customerId.cname.toUpperCase()}"></property>
通过另一个bean,获得属性,调用的方法
<property name="cname" value="#{customerId.cname?.toUpperCase()}"></property>
?. 如果对象不为null,将调用方法
-->
<bean id="customerId" class="com.spring.xml.spel.Customer" >
<property name="cname" value="#{customerId.cname?.toUpperCase()}"></property>
<property name="pi" value="#{T(java.lang.Math).PI}"></property>
</bean></span>
7.1.4.5集合注入
- 集合的注入都是给<property>添加子标签
数组:<array>
List:<list>
Set:<set>
Map:<map> ,map存放k/v 键值对,使用<entry>描述
Properties:<props> <propkey=""></prop>
普通数据:<value>
引用数据:<ref>
示例代码
public class CollData {
private String[] arrayData;
private List<String> listData;
private Set<String> setData;
private Map<String, String> mapData;
private Properties propsData;
public String[] getArrayData() {
return arrayData;
}
public void setArrayData(String[] arrayData) {
this.arrayData = arrayData;
}
public List<String> getListData() {
return listData;
}
public void setListData(List<String> listData) {
this.listData = listData;
}
public Set<String> getSetData() {
return setData;
}
public void setSetData(Set<String> setData) {
this.setData = setData;
}
public Map<String, String> getMapData() {
return mapData;
}
public void setMapData(Map<String, String> mapData) {
this.mapData = mapData;
}
public Properties getPropsData() {
return propsData;
}
public void setPropsData(Properties propsData) {
this.propsData = propsData;
}
@Override
public String toString() {
return "CollData [\narrayData=" + Arrays.toString(arrayData)
+ ", \nlistData=" + listData + ",\n setData=" + setData
+ ", \nmapData=" + mapData + ", \npropsData=" + propsData + "]";
}
}
配置文件
<bean id="collDataId" class="com.<span style="font-family:SimSun;">spring.</span>xml<span style="font-family:SimSun;">.</span>CollData" >
<property name="arrayData">
<array>
<value><span style="font-family:SimSun;">DD</span></value>
<value>D<span style="font-family:SimSun;">DD</span></value>
<value><span style="font-family:SimSun;">神</span></value>
<value><span style="font-family:SimSun;">keo</span></value>
</array>
</property>
<property name="listData">
<list>
<value><span style="font-family:SimSun;">张伟</span></value>
<value><span style="font-family:SimSun;">吕子乔</span></value>
<value><span style="font-family:SimSun;">展博</span></value>
<value>曾小贤</value>
</list>
</property>
<property name="setData">
<set>
<value><span style="font-family:SimSun;">你好</span></value>
<value><span style="font-family:SimSun;">哈哈</span></value>
<value><span style="font-family:SimSun;">嘻嘻</span></value>
</set>
</property>
<property name="mapData">
<map>
<entry key="jack" value="杰克"></entry>
<entry>
<key><value>rose</value></key>
<value>肉丝</value>
</entry>
</map>
</property>
<property name="propsData">
<props>
<prop key="高富帅">嫐</prop>
<prop key="白富美">嬲</prop>
<prop key="男屌丝">挊</prop>
</props>
</property>
</bean>
测试类
public class TestCllection {
@Test
public void demo01() throws Exception {
String xmlPath = "com/spring/xml/collection/beans.xml";
ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext(xmlPath);
CollData c = classPathXmlApplicationContext.getBean("collDataId",CollData.class);
System.out.println(c);
}
7.2基于注解
- 注解:就是一个类,使用@注解名称
- 开发中:使用注解 取代 xml配置文件。
1. @Component取代<bean class="">
@Component("id")取代 <beanid="" class="">
2.web开发,提供3个@Component注解衍生注解(功能一样)取代<bean class="">
@Repository:dao层
@Service:service层
@Controller:web层
3.依赖注入,给私有字段设置,也可以给setter方法设置
普通值:@Value("")
引用值:
方式1:按照【类型】注入
@Autowired
方式2:按照【名称】注入1
@Autowired
@Qualifier("名称")
方式3:按照【名称】注入2
@Resource("名称")
4.生命周期
初始化:@PostConstruct
销毁:@PreDestroy
5.作用域
@Scope("prototype") 多例
注意:
注解使用前提,添加命名空间,让spring扫描含有注解类
<pre class="programlisting"><span class="hl-directive" style="color:maroon;"><?xml version="1.0" encoding="UTF-8"?></span>
<span class="hl-tag"><beans</span> <span class="hl-attribute">xmlns</span>=<span class="hl-value">"http://www.springframework.org/schema/beans"</span>
<span class="hl-attribute">xmlns:xsi</span>=<span class="hl-value">"http://www.w3.org/2001/XMLSchema-instance"</span>
<span class="bold"><strong>xmlns:aop="http://www.springframework.org/schema/aop"</strong></span>
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
<span class="bold"><strong>http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"</strong></span>>
<em class="lineannotation"><span class="lineannotation"><!-- bean definitions here --></span></em>
<span class="hl-tag"></beans></span>
D.2.8 The |
示例代码:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 组件扫描,扫描含有注解的类 -->
<context:component-scan base-package="com.spring.annotation"></context:component-scan>
</beans>
@Component("userServiceId")
public class UserServiceImp implements UserService {
@Override
public void addUser() {
System.out.println("annotation");
}
}
测试类
public class TestAnnoIoc {
@Test
public void demo01() throws Exception {
String xmlPath = "com/spring/annotation/beans.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
UserService userService = (UserService) applicationContext.getBean("userServiceId", UserServiceImp.class);
userService.addUser();
}
}
分层代码示例:
Dao层:
public interface StudentDao {
void save();
}
@Repository("studentDaoId")
public class StudentDaoImpl implements StudentDao {
@Override
public void save() {
System.out.println("dao");
}
}
Service层
public interface StudentService {
void addStudent();
}
@Service
public class StudentServiceImpl implements StudentService {
private StudentDao studentDao;
@Autowired
@Qualifier("studentDaoId")
public void setStudentDao(StudentDao studentDao) {
this.studentDao = studentDao;
}
@Override
public void addStudent() {
studentDao.save();
}
}
Web(Control)层
@Controller("studentActionId")
public class StudentAction {
@Autowired //默认按照类型
private StudentService studentService;
public void execute() {
studentService.addStudent();
}
}
匹配示意图:
图一
图二
图三
如果注解与XML配置混合使用呢??
1.将所有的bean都配置xml中
<beanid="" class="">
2.将所有的依赖都使用注解
@Autowired
默认不生效。为了生效,需要在xml配置:<context:annotation-config>
总结:
注解1:<context:component-scanbase-package=" ">
注解2:<context:annotation-config>
1.一般情况两个注解不一起使用。
2. “注解1”扫描含有注解(@Component等)类,注入注解自动生效。
“注解2”只在xml和注解(注入)混合使用时,使注入注解生效。
学习到这里,你已经对Spring有了一定的认识。下一篇博客,我将继续整理spring的知识点,介绍Spring另一个核心:AOP。