这一篇文章我将和大家一起回顾整个Spring框架技术,由于内容较多,内容共分为三大部分。每一篇都从简到难地安排了一些小知识点,东西是当时我老师讲的,现在将知识点都整理下来,供大家一起讨论学习,也方便以后自己复习。如果有不对的地方欢迎大家指正。
1.初识Spring框架,声明周期和延时加载…
2.注入,自动装配,注入集合类型,注入properties类型…
3.Spring简介,对象获取方式,对象声明周期…
<1>.初识Spring框架,声明周期和延时加载…
1. 框架
框架是一套已经编写好的程序结构,开发者在使用框架之后,可以在此基础之上进行开发,而不必关心偏底层的问题。
框架通常可以提高开发效率,一定程度上还解决了一些其它的问题,可能是性能的问题,或者数据安全的问题,或者程度的可维护性的问题等等。
框架具体的表现就是一系列的jar包,并且,可能改变原有的编程方式或流程。
普通的jar包,例如dom4j
、mysql-connector
等,只是实现了某个功能,相当于是一套工具。
2. 课程任务
- Spring框架
- SpringMVC框架
- MyBatis框架
3. Spring框架
3.1. 作用
创建和管理对象。
传统的创建对象的方法是:Object obj = new Object();
使用Spring框架后:Object obj = 框架.getXXX();
即:开发者无需关注对象的创建过程,改由框架来创建,当需要对象时,通过框架获取即可。
传统的管理对象可能有:student.setName("张三同学");
使用Spring框架后,无需执行相关代码,通过配置,获取对象时,相关属性就已经有值了。
3.2. 项目准备
先创建Maven项目,勾选Create a simple project
,Group Id
为cn.tedu.spring
,Artifact Id
为SPRING-01
,Packaging
选择war
,创建好项目后,默认项目是出错的,需要生成web.xml
文件。
使用Spring之前,需要添加相关依赖,artifactId
为spring-webmvc
,且groupId
是org.springframework
,版本通常选择3.2或以上版本,但,目前尚不推荐使用5.x版本。
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.9.RELEASE</version>
</dependency>
以上代码,应该添加到项目的pom.xml
的<dependencies>
节点的内部。
然后,下载得到applicationContext.xml
文件,复制到项目中的src\main\resources
文件夹下:
这里我将applicationContext.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"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd">
<bean id="date" class="java.util.Date" />
<bean id="user" class="cn.tedu.spring.User" /> <!-- 要求类中要有无参构造方法,对构造方法的权限没有要求 -->
<!-- 2. 类中存在静态工厂方法 -->
<bean id="calendar" class="java.util.Calendar" factory-method="getInstance"></bean>
<bean id="huaweiphone" class="cn.tedu.spring.HuaWeiphone" factory-method="create"/>
<!-- -->
<bean id="carFactory" class="cn.tedu.spring.CarFactory" />
<bean id="car" class="cn.tedu.spring.Car" factory-bean="carFactory" factory-method="makeCar"></bean>
<bean id="student" class="cn.tedu.spring.Student" scope="singleton" lazy-init="true" init-method="init" destroy-method="destroy"/> <!--懒汉式的初始化,在加载Spring的配置文件之前,就创建完对象 -->
</beans>
3.3. 通过Spring获取对象–类中存在无参数构造方法(常用)
在Spring的配置文件(applicationContext.xml
)中,添加:
<bean id="date" class="java.util.Date">
</bean>
以上配置中,class
表示“类”,取值应该是类的全名,即包名和类名,id
是自定义的名称,通常使用类名并且首字母改为小写,例如类名是Date
,则id值为date
,如果类名是Student
,则id
值为student
。
完成配置后,就可以在程序中,通过Spring根据date
名称获取java.util.Date
的对象,可以在src\main\java
中创建可执行的Java类:
package cn.tedu.spring;
public class SpringTest {
public static void main(String[] args) {
}
}
然后,编写程序:
public static void main(String[] args) {
// 加载Spring的配置文件,获取Spring容器
ApplicationContext ac
= new ClassPathXmlApplicationContext(
"applicationContext.xml");
// 通过Spring容器获取对象
Date date = (Date) ac.getBean("date");
// 测试输出
System.out.println(date);
}
自定义
User
类,在Spring的配置文件中添加配置,最终,在程序中,获取User
类的对象。
以上操作,要求类中存在无参数的构造方法,如果不具备条件,则:
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'user' defined in class path resource [applicationContext.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [cn.tedu.spring.User]: No default constructor found; nested exception is java.lang.NoSuchMethodException: cn.tedu.spring.User.<init>()
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [cn.tedu.spring.User]: No default constructor found; nested exception is java.lang.NoSuchMethodException: cn.tedu.spring.User.<init>()
Caused by: java.lang.NoSuchMethodException: cn.tedu.spring.User.<init>()
这种做法对构造方法的访问权限并没有任何要求,即使是private
权限,也不影响Spring创建对象!
此次实现的代码中,关于ac
变量,会提示警告:ac is never closed
,即:推荐调用ac.close()
以释放资源,但是,ApplicationContext
接口中并没有声明close()
方法,所以,应该将ac
的类型声明为AbstractApplicationContext
。
3.4. 通过Spring获取对象–类中存在静态工厂方法(不常用)
**工厂方法:**调用后可以返回类的对象的方法,也可以理解为生产对象的方法。
以Calendar
为例,它是一个抽象类,是不可以直接通过new 构造方法()
此类语法创建对象的!但是,在这个类中,有static Calendar getInstance()
方法,这个方法,就称之为Calendar
类的静态工厂方法!
在Spring的配置文件中,配置:
<bean id="calendar"
class="java.util.Calendar"
factory-method="getInstance"></bean>
以上配置中,factory-method
属性的值是静态工厂方法的名称。
配置时,无论是类的全名,还是方法的名称,都必须是已知条件。
练习:自定义类HuaWeiPhone,通过静态工厂方法,获取该类的对象!
关于类:
package cn.tedu.spring;
public class HuaWeiPhone {
// 使得当前类不存在无参数的构造方法
public HuaWeiPhone(Object obj){
super();
}
// 静态工厂方法
public static HuaWeiPhone create() {
return new HuaWeiPhone(null);
}
}
关于配置:
<bean id="huaWeiPhone"
class="cn.tedu.spring.HuaWeiPhone"
factory-method="create"></bean>
3.5. 通过Spring获取对象–存在实例工厂方法(不常用)
实例工厂方法:通过某个实例(对象)调用的方法,并且,这个方法可以返回某个类的对象,是生产对象的方法。
假设存在某类需要被获取对象,不满足前序的2种条件:
public class Car {
public Car(Object obj) {
}
}
则需要另一个类中存在工厂方法,可以创建它的对象
public class CarFactory {
public Car makeCar() {
return new Car(null);
}
}
在配置时:
<bean id="carFactory"
class="cn.tedu.spring.CarFactory"></bean>
<bean id="car" class="cn.tedu.spring.Car"
factory-bean="carFactory"
factory-method="makeCar">
</bean>
以上配置中,factory-bean
的值是工厂类的<bean>
节点的id
属性值。
3.6. 通过Spring获取对象–小结
通过Spring创建对象,然后从Spring容器中获取对象,需要:
- 类中存在无参数的构造方法;
- 类中存在静态的工厂方法;
- 存在实例工厂方法。
以上3种方式中,第2种和第3种的使用频率较低,原因是满足条件的类较少。
3.7. 由Spring管理的对象的作用域
单例:单一的实例,即在同一时刻,某个类的对象是唯一的!
由Spring所管理的对象,默认都是单例的,在配置时,通过scope
属性可以配置是否单例,默认取值为singleton
,当取值为prototype
时,是非单例的!
<bean id="student"
class="cn.tedu.spring.Student"
scope="prototype"></bean>
单例模式可以区分为:懒汉式、饿汉式。
默认情况下,由Spring管理的单例对象是饿汉式的,通过lazy-init
属性可以调整,该属性的值是布尔类型。
<bean id="student"
class="cn.tedu.spring.Student"
scope="singleton"
lazy-init="true"></bean>
3.8. 由Spring管理的对象的生命周期
仅由Spring管理的、单例的对象存在生命周期问题!
开发者可以在任何自定义的、由Spring管理的类中添加初始化方法和销毁方法,方法必须是void
和无参数的,例如:
public class Stduent {
// 初始化方法
public void init() {
System.out.println("Student.init()");
}
// 销毁方法
public void destroy() {
System.out.println("Student.destroy()");
}
}
然后,在Spring的配置文件中进行配置:
<bean id="student"
class="cn.tedu.spring.Student"
init-method="init"
destroy-method="destroy"></bean>
注意:对于非单例的对象而言,生命周期方法是没有意义的。
3.9. 通过SET方式注入属性的值
基本概念:通过Spring的配置,确定某个类中的某个属性的值,使得最终获取对象时,属性是已经被赋值的。
假设存在UserDao
类,在类中有String username
和String password
表示访问数据库的用户名和密码:
public class UserDao {
// 模拟:访问数据库的用户名
String username;
// 模拟:访问数据库的密码
String password;
}
需要注入值的属性,必须有set方法,即设置它的值的方法,且方法名称必须以set
作为前缀:
public void setUsername(String u) {
username = u;
}
然后,在Spring的配置文件中:
<bean id="userDao"
class="cn.tedu.spring.UserDao">
<property name="username"
value="root">
</property>
</bean>
即:添加子级<property>
节点,在该节点,配置name
和value
,其中,name
表示属性,value
表示值。
注意:在配置的name时,值应该是需要注入的属性的set方法名称中不包含set的部分,且首字母是小写的!
其它
1. 关于Maven中依赖出错
在添加依赖后,下载到的jar包文件可能是已损坏的,或数据不完整的,可能表现为:下载的jar包的数量不正确,或者,编写代码时,某个类无法识别等……
解决方案:
- 打开Eclipse的设置,找到
Maven
>User Settings
,面板中的Local Repository
就是本地仓库文件夹; - 关闭Eclipse,因为已经打开的项目可能引用了本地仓库文件夹中的某个jar包,如果Eclipse正在运行,可能导致后续的删除操作无法执行;
- 打开本地仓库文件夹,删除出错的jar包文件(通常jar包文件对于新生来说不易于查找,所以,简单的操作方式就是将整个本地仓库文件夹全部删除);
- 打开Eclipse,找到需要开发的项目,点击右键,选择
Maven
>Update Project
,在弹出的对话框中,选中Force update ...
选项,然后,开始更新即可。
2. Resource leak
Resource leak表示“内存溢出”(内存泄露)。
模拟情景:假设存在D:/a.txt
,在程序中,通过FileInputStream fis
访问该文件,在访问过程中,如果出现异常,导致程序结束,然后,JVM中垃圾回收机制尝试回收垃圾时,找到了fis
,但是,前序fis
并没有正常关闭,仍然连接着硬盘上的a.txt
文件,在JVM看来,这个fis
仍处于使用状态,不是垃圾!但是,以程序员的角度来看,fis
是一个变量,当程序崩溃时,这个变量就已经无法继续使用,就是个垃圾!所以,就会出现“已经无法继续使用的对象,却不会被视为垃圾数据,无法被回收!”
如果以上类似的垃圾数据越来越多,就会导致可用内存越来越少,当达到极端状态时,就会出现“内存溢出”!
所以,其实,少量的内存溢出,并没有明显的危害!但是,作为开发者,应该尽量的避免任何可能出现的内存溢出!
解决内存溢出的核心:尽早释放不再使用的资源,例如流、数据库访问的相关对象、XML的读写工具等连接型资源,对于可能抛出异常的代码,应该添加finally
代码块,并在其中释放资源。
3. 单例模式示例
public class King {
private static King king;
private King() {
}
public static King getKing() {
if (king == null) {
king = new King();
}
return king;
}
}
以上是懒汉式单例模式的代码,且,没有解释线程安全问题。
<2>.注入,自动装配,注入集合类型,注入properties类型…
前课
- Spring的作用:创建和管理对象
- 配置无参数构造方法的类
- Spring管理对象的作用域与生命周期
- 通过SET方法为属性注入值
1. 【常用】通过SET方法注入属性的值(续)
如果需要注入的属性的值并不是基本值(基本数据类型或String),则值需要配置为一个<bean>
,且,注入值时,使用ref="bean-id"
来确定属性的值:
小结:为属性注入值时,如果类型是基本型,使用value进行配置,如果类型是引用,需要配置另一个bean来创建值的对象,然后通过ref进行配置。
2. 【不常用】通过构造方法注入属性的值
首先,类中应该存在带参数的构造方法:
public class User {
public String name;
public String from;
public User(String name, String from) {
super();
= name;
this.from = from;
}
}
在配置时,通过<constructor-arg>
配置构造方法的参数的值,如果有个参数,则需要多个节点,每个节点配置1个属性,且每个节点都必须添加index
属性,表示配置的是第几个参数,取值为从0开始编号的数字,根据值的类型不同,继续配置value
或ref
来决定属性的值:
<bean id="user"
class="cn.tedu.spring.User">
<constructor-arg index="0"
value="LiuGB">
</constructor-arg>
<constructor-arg index="1"
value="HeBei">
</constructor-arg>
</bean>
3. 注入集合类型的值
例如存在类:
public class SampleBean {
public List<String> names;
public void setName(List<String> names) {
s = names;
}
}
然后,添加配置:
<bean id="sampleBean"
class="cn.tedu.spring.SampleBean">
<property name="names">
<list>
<value>Jame</value>
<value>Lucy</value>
<value>David</value>
<value>Tom</value>
<value>Alex</value>
</list>
</property>
</bean>
因为names
属性的类型是List
,所以,在注入值时,<property>
节点中添加子级的<list>
节点进行配置,在<list>
中的每组<value>
节点表示1个值。
如果属性是Set
类型的,则使用<set>
节点进行配置即可:
<property name="cities">
<set>
<value>Hangzhou</value>
<value>Beijing</value>
<value>Shanghai</value>
<value>Shenzhen</value>
<value>Guangzhou</value>
</set>
</property>
如果属性是Map
类型的,则需要使用<map>
及其子级的<entry>
节点进行配置:
<property name="session">
<map>
<entry key="username" value="Jack"/>
<entry key="password" value="1234"/>
<entry key="from" value="Nanjing"/>
</map>
</property>
还有Properties
类型,通常在使用时,会自定义一个???.properties
文件,例如:
url=jdbc:mysql://192.168.0.251:3306/db_name?useUnicode=true&characterEncoding=utf8
driver=com.mysql.jdbc.Driver
username=root
password=root
initialSize=2
maxActive=10
然后,通过Spring框架读取该文件的信息:
<util:properties id="config"
location="classpath:db.properties">
</util:properties>
以上<util:properties>
节点本质上也是一个<bean>
,在注入值时:
<property name="dbConfig"
ref="config">
</property>
当然,Properties
类型的节点是可以直接配置的,例如:
<property name="dbConfig">
<props>
<prop key="name">Jack</prop>
</props>
</property>
事实上,关于List
、Set
、Map
也存在<util:list>
等类似节点,使用频率较低。
以上2种为Properties
类型的数据注入值的做法都是有用的!而为List
、Set
、Map
类型的数据注入值的应用场景相对较少。
4. 自动装配(Auto-wire)
自动装配表示由Spring自动的为属性注入值,即:无需配置各<property>
节点!可以解决需要注入多个值时添加多个<property>
节点导致的配置项太多的问题!
当需要自动装配时,为<bean>
节点添加autowire
属性的配置即可,常用的取值有byName
和byType
:
当取值为byName
时
表示“根据名称实现自动装配”,即:当某个<bean>
配置了autowire="byName"
时,Spring会检索当前类中的SET系列方法,根据SET方法的名称还原出属性名,并且尝试在Spring容器中找到bean-id相同的对象,如果找到,则自动为这些属性赋值,如果没有找到,也不会报告任何错误,只是相关属性没有被赋值而已!这种做法本质上还是通过SET方式注入的,所以,需要被注入的属性一定要有SET方法!而SET方法的名称一定与值对应的bean-id是匹配的!
当取值为byType
时
顾名思义,当取值为byType
时,会“根据类型实现自动装配”,例如private IUserDao userDao;
时,会尝试在Spring容器中查询类型符合IUserDao
类型的<bean>
,如果找到,则自动装配,否则,将跳过。
使用这种做法时,无需关心各个名称(属性名、方法名、bean-id),但是,需要保证“能匹配的bean只有1个”,否则,会出现NoUniqueBeanDefinitionException
,并提示例如:expected single matching bean but found 2: userDao2,userDao
。
小结
自动装配还有其它模式,暂不需要了解。
记住byName
和byType
的意义,及byType
的注意事项。
自动装配虽然简单,但是,存在“是否注入值不明确”的问题,即:只能看到哪些<bean>
配置了autowire="byName"
或autowire="byType"
,但是,这些类中的属性是否成功的注入了值、哪些属性是需要注入值的……等问题并不明确,也无从可查,所以,关于这种自动装配的做法是不推荐的!
5. Spring表达式
Spring表达式的基本格式是#{名称}
,用于表示某个值,甚至,值可以是来自另一个<bean>
的某个属性!
当某个注入的属性值是通过Spring表达式得到的,则应该配置为value=#{}
格式。
关于Spring表达式:
- 如果获取另一个
<bean>
中的某属性值,则使用#{bean-id.属性名}
; - 如果获取另一个
<bean>
中的某List集合中的某个值,则使用#{bean-id.List集合名[索引]}
; - 如果获取另一个
<bean>
中的某Map集合中的某个值,则使用#{bean-id.Map集合名.key}
,还可以是#{bean-id.Map集合名['key']}
。
1. 什么时候需要自定义构造方法?
如果某个类没有显式的添加构造方法,则编译器会自动添加公有的、无参数的构造方法,例如:
public class User {
}
等效于:
public class User {
public User() {
super();
}
}
如果显式的添加了构造方法,则编译器就不会添加任何构造方法!
通常,需要自定义构造方法的原因:不允许使用公有的、无参数的构造方法。
具体的表现:
- 限制创建对象,例如:单例模式;
- 强制要求得到某数据;
- 快速创建对象、确定某些属性的值。
2. List和Set的特性
List:顺序的,先存入的数据在前,后存入的数据在后;元素可重复;
Set:散列的,先存入的数据不一定在前,后存入的数据不一定在后;元素不可重复,如果尝试添加相同的数据,在Set中并不会不多项该元素,关于“是否相同”的评定依据是“2个数据的equals()对比结果为true,并且hashCode()的返回值必须相同”!
Set的本质是一个只关心key不关心value的Map!
Model:DAO
View:html/jsp
Controller:Servlet
View > Controller > Model(Service + DAO)
Service:登录
Service:注册
DAO:根据用户名查询用户信息
<3>.Spring简介,对象获取方式,对象生命周期…
1. 前2天小结
- 【理解】通过Spring获取对象的3种条件:无参构造方法、静态工厂方法、实例方法;
- 【理解】由Spring管理的对象的作用域及生命周期:单例、懒加载、生命周期方法;
- 【重要】通过SET方式注入属性的值,理解value和ref的使用;
- 【了解】通过构造方法注入属性的值;
- 【了解】注入集合类型的属性的值,包括:List / Set / Map;
- 【重要】注入Properties类型的属性的值,读取*.properties文件;
- 【理解】自动装配的作用,取值为byName与byType的特性;
- 【重要】Spring表达式
2. Spring注解(Annotation)
2.1. 基本概念
例如@Override
就是注解,在Spring中定义了一些注解,可以取代在Spring的XML文件中的配置!
2.2. 通过Spring获取对象
案例目标:创建cn.tedu.spring.dao.UserDao
类,然后,创建cn.tedu.spring.test.SpringTest
类,通过Spring获取UserDao
的对象。
在Spring中,有几种通用注解:
- @Component
- @Controller
- @Service
- @Repository
这些注解是添加在类的声明之前的,表示这个类是一个“组件”,是希望由Spring进行管理的!
以上4个注解中,@Component
表示“通用组件类”,@Controller
表示“控制器类”,@Service
表示“业务类”,@Repository
表示“数据访问类/持久层处理的类”,这4个注解只有语义的区别,从功能和用法上来说,是完全一样的!即,如果愿意的话,可以用@Service
注解添加在控制器类的声明之前,但是,不推荐这样做。
仅仅只是添加注解是不够的,还需要在Spring的配置文件中开启组件扫描:
<context:component-scan
base-package="cn.tedu.spring.dao" />
以上配置中,base-package
表示根包,即当配置为cn.tedu.spring
时,其子级包例如cn.tedu.spring.dao
或cn.tedu.spring.service
等都在扫描范围之内!
如果没有显式的指定bean-id,默认为使用类名且首字母改为小写,例如UserDao
类的bean-id就是userDao
。
以上注解都可以添加配置,例如@Service("bean-id")
。
小结:通用注解共4个,其功能、用法都是完全相同的,只是表达的语义不同,添加的注解的类,并且在组件扫描范围之内,就会被Spring所管理,在配置组件扫描时,配置的包是“根包”,其范围不宜过大,在添加注解时,还可以自定义bean-id。
2.3. 作用域与生命周期
由Spring管理的对象,默认是饿汉式的单例的,通过在类的声明之前添加注解@Lazy
可以调整:
@Component("userDao")
@Lazy(true)
public class UserDao {
}
还可以通过@Scope("singleton")
或@Scope("prototype")
注解调整是否为单例的:
@Service
@Scope("prototype")
public class UserService {
}
关于生命周期方法,依然是先自定义生命周期方法,在初始化方法之前添加@PostConstruct
注解,在销毁方法之前添加@PreDestroy
注解,这2个注解都是Java EE的注解,来自javax
包下,所以,在使用之前,需要为当前项目添加Tomcat运行环境,代码部分例如:
@Component("userDao")
public class UserDao {
public UserDao() {
System.out.println("UserDao的构造方法被执行!");
}
@PostConstruct
public void init() {
System.out.println("UserDao.init()");
}
@PreDestroy
public void destroy() {
System.out.println("UserDao.destroy()");
}
}
注意:如果导入他人的项目,或者本机更换了Tomcat软件,都需要重新勾选项目属性中的Targeted Runtimes中的Tomcat。
2.4. 【重要】自动装配
假设在UserDao
中存在public void findUserByUsername()
方法,然后,在UserService
中声明了private UserDao userDao;
属性,并且,存在public void login()
方法,在方法内部,调用了userDao
的findUserByUsername()
方法:
@Component("userDao")
public class UserDao {
public void findUserByUsername() {
System.out.println("UserDao.findUserByUsername()");
}
}
@Service
public class UserService {
private UserDao userDao;
public void login() {
System.out.println("UserService.login()");
userDao.findUserByUsername();
}
}
在需要自动装配属性值的属性之前,添加@Autowired
注解,就可以实现自动装配:
@Autowired
private UserDao userDao;
注意:使用注解的自动装配不需要为属性添加SET方法!
添加@Autowired
实现自动装配,其装配方式是byType
的,所以,在使用时,需要确保“其对应的值在Spring容器中应该是有且仅有1个的”!
通过@Resource
注解也可以实现自动装配!它是优先根据byName
实现自动装配,在没有显式的指定bean-id的情况下,如果无法byName
装配,则会尝试根据byType
实现自动装配。
在实际使用时,可以自由选取以上2个注解中的任何一个!因为,在实际应用中,命名应该是规范的,并且,匹配类型的也应该是有且仅有1个。
以上2个注解中,@Autowired
是Spring的环境中的注解类,而@Resource
是Java EE环境中的注解类。