【JavaWeb_Part08】白娘子你就算淹了这深圳,我他妈也要去玩我的 Spring

来源:互联网 发布:淘宝售后处理时间 编辑:程序博客网 时间:2024/04/30 00:32

开篇

mmp,今天上班又迟到了一个小时。一下雨这鬼路上就堵车,简直了。。好了,不吐槽了,昨天挖的坑,今天是时候填上了。内容可能有点多,肾功能不强大者勿看0.0。

常见的几种注入方式

1. Set 方式注入

set 方式注入是除了注解以外最常用的一种方式,我们昨天所说的就是通过 set 方式注入属性值的,具体实现如下:
在 applicationContext.xml中配置:

 <!-- 通过 set 方式注入值--><bean id="user" class="com.student.spring.bean.User">    <property name="name" value="二花"/>    <property name="address" value="大森林"/></bean>

在实体类中提供 set 方法

public class User {    private String name;    private String address;    public void setName(String name) {        this.name = name;    }    public void setAddress(String address) {        this.address = address;    }    @Override    public String toString() {        return "User{" +                "name='" + name + '\'' +                ", address='" + address + '\'' +                '}';    }}

测试结果:
这里写图片描述
注意:

  1. 必须要提供 set 方法,get 方法可以不提供。
  2. 通过配置 Spring 就可以实现帮我们创建对象的实例,这说明了什么?说明 Spring 底层是通过反射来帮我们创建对象的实例的,如果不提供 set 方法,Spring 将无法通过反射来获取到 setXXX() 方法来帮我们注入值。
  3. 提供 toString 方法仅仅只是为了打印结果,并没有其他意图。

2. 通过构造器注入值

在 User 对象中添加如下构造函数:

public class User {    private String name;    private String address;    public User(String name, String address) {        this.name = name;        this.address = address;    }    @Override    public String toString() {        return "User{" +                "name='" + name + '\'' +                ", address='" + address + '\'' +                '}';    }}

在applicationContext.xml 文件中做如下配置:

<!-- 通过 构造方法的 方式注入值--><bean id="user" class="com.student.spring.bean.User">    <constructor-arg name="name" value="二花"/>    <constructor-arg name="address" value="大森林"/></bean>

测试结果:
这里写图片描述

结果是正常的,不过通过构造函数注入时,除了可以通过

<constructor-arg name="name" value="小明"/>

这种方式外,还可以通过索引来注入,比如把配置文件更改成如下的方式:

<!-- 通过 构造方法的 方式注入值--><bean id="user" class="com.student.spring.bean.User">     <constructor-arg index="0" value="二花"/>     <constructor-arg index="1" value="广东深圳"/> </bean>

结果同上面是一样的。(提示:索引从 0 开始)
这里写图片描述

注意

这里全部都是用的 value ,还记得昨天的文章中有一个 ref 么?为什么要用 value 而不用 ref 请自行去上一篇文章中弄清楚。

假设 User 对象中有另外一个 对象 “Car”, 这个时候我们应该如何注入?如何注入我们试试就知道了。
新建一个 Car 对象

public class Car {    private String cname;    private Double cprice;    public void setCname(String cname) {        this.cname = cname;    }    public void setCprice(Double cprice) {        this.cprice = cprice;    }}

在 User 对象里面添加

private Car car;public User(String name, String address, Car car) {    this.name = name;    this.address = address;    this.car = car;}

在配置文件 applicationContext.xml 中做如下配置:

<!-- 通过 set 方式注入值--><bean id="car" class="com.student.spring.bean.Car">    <property name="cname" value="保时捷"/>    <property name="cprice" value="2000000"/></bean><!-- 通过 构造方法的索引 方式注入值--><bean id="user" class="com.student.spring.bean.User">    <constructor-arg index="0" value="二花"/>    <constructor-arg index="1" value="广东深圳"/>    <!-- 引用上面 定义的 car-->    <constructor-arg index="2" ref="car"/></bean>

结果
这里写图片描述

我想,到这里,ref 和 value 的用法你应该了解了。如果还不知道什么区别的话,那你这样记吧。

value 是传值的,ref 是传引用的。
这句话可能不太严谨,但是对初学者来说,还是比较好记住的。

3. 其他的注入方式

注入的方式还有

SpEL 表达式注入通过 P 标签注入通过注解注入(重要)

其中 SpEL 表达式 和 p 标签在开发中基本不会用到,这里就不做讲解了。而注解注入,这个是比较重要的知识点,留在后面去说。注解注入也是我们以后开发中最主流的注入方式。

p 标签的注入方式(了解)

<bean id="car" class="com.student.spring.bean.Car" p:cname="奔驰" p:cprice="125000"/>    <!-- 通过 p 标签 方式注入值--><bean id="user" class="com.student.spring.bean.User" p:name="宇文玥" p:address="青山院" p:car-ref="car"/>

注意:通过 p 标签注入,一定要提供 set 方法,否则无法注入。
这里写图片描述

SpEL 的代码我就不写了,有需要的可以去看一些文档。自己要学会举一反三。

注入几种特殊类型

1. 注入数组类型

<!-- 注入数组--><bean id="sptype" class="com.student.spring.bean.SpType">    <property name="strs">        <list>            <value>hello</value>            <value>world</value>        </list>    </property></bean>

SpType.java

public class SpType {    private String[] strs;    public void setStrs(String[] strs) {        this.strs = strs;    }}

这里写图片描述

2. 注入 List

这个套路和注入数组一毛一样,这里就只给出配置文件和截图了。

 <bean id="sptype" class="com.student.spring.bean.SpType">     <!-- 注入数组-->    <property name="strs">        <list>            <value>hello</value>            <value>world</value>        </list>    </property>    <!-- 注入集合-->    <property name="lists">        <list>            <value>小明</value>            <value>熊大</value>        </list>    </property></bean>

这里写图片描述

3. 注入Map

这个和上面的两者稍有区别。也不废话了,直接上配置文件。

<bean id="sptype" class="com.student.spring.bean.SpType">   <!-- 注入数组-->    <property name="strs">        <list>            <value>hello</value>            <value>world</value>        </list>    </property>    <!-- 注入 list-->    <property name="lists">        <list>            <value>小明</value>            <value>熊大</value>        </list>    </property>    <!-- 注入map:map 是以键值对的形式存在的-->    <property name="maps">        <map>            <entry key="key1" value="value1"/>            <entry key="key2" value="value2"/>            <entry key="key3" value="value3"/>        </map>    </property></bean>

运行截图:
这里写图片描述

4. 注入 Set

套路和 List 已经数组一样,只不过要注意,Set 没有重复的值。

<!-- 注入 set ,这里给 Set 注入了四个值,实际打印只有三个,去掉了重复的 xixi--><property name="sets">    <set>        <value>haha</value>        <value>hehe</value>        <value>xixi</value>        <value>xixi</value>    </set></property>

截图:
这里写图片描述

5. 注入属性文件

 <property name="prop">  <props>        <prop key="key">隔壁老王</prop>        <prop key="key2">隔壁老宋</prop>    </props></property>

具体测试我就不测试了,挺简单的,有兴趣自己动手,丰衣足食。

Spring 重要的开发方式之注解开发

啥是注解我也就不解释了,不知道的话,推荐你们去重新温习一下 Java 的基础知识。

1. 注解入门

使用注解开发,能够极大的方便我们的开发,所以这也是我们实际开发中必须掌握的一门技术。要使用注解进行开发,我们需要引入 Spring 框架的另外一个包

spring-aop-4.0.2.jar

此时修改我们的 UserServiceImpl.java,在类的上面添加如下注解

//这行注解的功能就相当于<bean id="userService" class="com.student.spring.service.UserServiceImpl">@Component("userService")public class UserServiceImpl implements UserService {    @Override    public void save() {        System.out.println("service 层使用注解");    }}

如果要使该注解生效,我们需要告诉 Spring 容器我们使用了注解。所以我们还需要在配置文件中加上一句话:(开启注解扫描)

 <!--开启注解扫描 base-package 是指扫描哪一个包下面的注解--> <context:component-scan base-package="com.student.spring.service"/>

运行结果:
这里写图片描述

运行结果和我们在配置文件中配置并无其他区别。通过注解,我们不需要再配置文件中在配置数不清的 bean,大大节省了我们的开发时间,也提升了我们的开发效率。

2. 注解功能讲解

@Component 注解是什么意思呢?
Component 是组件的意思,作用在类上的。在我们的 MVC 开发模式中,WEB 层,Service 层以及 Control 层都可以使用该注解。但是为了满足单一职责原则,从该注解又衍生出三个注解:

@Controller 作用在类上,WEB 层使用@Service 作用在类上,Service 层使用@Repository 作用在类上,Dao 层使用

这三个注解本身就是为了使各个模块的功能更加清晰,虽然你使用 @Component 也没错,但是谁也不能保证 Spring 的团队后面不会对该注解进行改动,所以为了避免以后出现不必要的麻烦,还是使用功能分工明确的那三个注解。

So?我们的上面的例子也可以使用 @Service 注解来代替:

//@Component("userService")@Service("userService")public class UserServiceImpl implements UserService {    @Override    public void save() {        System.out.println("service 层使用注解");    }}

实现的效果完全一样。

3. 使用注解注入属性

上面只是讲了解决了配置文件中 bean 标签的简化配置

<bean id="xxx" class="xxx">

那如果我们要注入引用类型和基本数据类型呢?难道没有吗?错,Spring 当然给我们也提供了注解的方式。看下面的几个注解:

@AutoWired@Qualifier@Value 

首先从最下面的注解说起

3.1 如果是要注入普通的数据类型,那么非 Value 注解莫属。

修改 UserServiceImpl.java

@Service("userService")public class UserServiceImpl implements UserService {//    @Value("二花")    @Value(value = "二花")    private String name;    @Override    public void save() {        System.out.println("service 层使用注解:===" + name);    }}

注意:
Spring 所提供的注解属性值全部都是 value
在注解只有一个属性的前提下,”value = ” 可省略不写
上面的 @Value(value=”二花”) 和 @Value(“二花”) 是等价的
同理 @Service(“userService”) 同样也和 @Service(value=”userService”) 等价
使用注解后,set 方法可以省略。

这里写图片描述

3.2 注入引用类型

如果是注入引用类型的话,就要看 @AutoWired 和 @Qualifer 这两个注解了。

@AutoWired //按类型装配@Qualifer  //强制使用名称注入

先说 @AutoWired 注解
更改 UserDaoImpl.java,要把 UserDaoImpl 也交给 Spring 去管理,必须要加上注解 @Repository 注解。

@Repository(value = "userDao")public class UserDaoImpl implements UserDao {    @Override    public void save() {        System.out.println("dao 层操作数据库去保存用户数据");    }}

再改 UserServiceImpl.java

@Service(value = "userService")public class UserServiceImpl implements UserService {    @Autowired    private UserDao userDao;    @Override    public void save() {        System.out.println("service 层保存用户");        userDao.save();    }}

先不谈 AutoWired 的功能,我们先看结果。
测试结果:
这里写图片描述

嗯,老铁,没毛病。AutoWired 是自动装配的,它默认是按照类型装配的,如果我们把

//在 UserServiceImpl 中@AutoWiredprivate UserDao userDao1;//在 UserDaoImpl 中@Repository("userDao")

结果和上面一样,这是为什么呢?是因为使用了 AutoWired 注解后,他并不是根据 id 去找,而是根据类型去找的,所以不管你更改成什么名字,ud,xxx 等等,都是可以注入成功的。但是这样是会有一个弊端的,如果一个接口有多个实现类,那么此时使用 AutoWired 进行自动装配肯定会出错。那么如何解决上面的问题呢?

当然有解决办法,我们不乱写名字不就可以了么?那么我们的另外一个注解 @Qualifer,这个注解的意思就是强制使用名称去注入

更改 UserDaoImpl.java 和 UserServiceImpl.java 中的代码

@Repository(value = "xxx")public class UserDaoImpl implements UserDao {    @Override    public void save() {        System.out.println("dao 层操作数据库去保存用户数据");    }}
@Service(value = "userService")public class UserServiceImpl implements UserService {    @Qualifier(value = "xxx")    @Autowired    private UserDao userxxx;    @Override    public void save() {        System.out.println("service 层保存用户");        userxxx.save();    }}

测试结果:
这里写图片描述

这样就达到了我们的目的。一个是按类型,一个强制按名称,这两个注解同时使用,只能得出正确的结果。

3.3 Java 提供的 Resource 注解

如果一个接口有多个实现类,那么我们就跟上面一样,需要同时写两个注解,那么这好像一点也不程序员,不满足我们程序员的风格,能不能再简单一点呢?当然可以,Java 中有一个注解是得到了 Spring 的支持了的,他就是 Resource 注解,这个注解的功能就相当于上面的 AutoWired 注解和 Qualifer 注解同时使用。

这样更改 UserServiceImpl.java

@Service(value = "userService")public class UserServiceImpl implements UserService {    @Resource(name = "xxx")    private UserDao userxxx;    @Override    public void save() {        System.out.println("service 层保存用户");        userxxx.save();    }}

这里写图片描述

图片展示的结果已经说明了一切,一切尽在不言中。

bingo!此处应该有掌声。。。(鸦雀无声),好吧,此时无声胜有声也行。(自抱自泣.jpg)

3.4 其他注解

  1. Bean的作用范围注解
    1. 注解为@Scope(value=”prototype”),作用在类上。值如下:
    2. singleton – 单例,默认值
    3. prototype – 多例

  2. Bean的生命周期的配置(了解)
    注解如下:
    1. @PostConstruct – 相当于init-method
    2. @PreDestroy – 相当于destroy-method

OK,完美收工。

结尾

一点注解和注入方式就讲了这么多,好啦,下面的东西留到下篇文章吧,毕竟需要消化一下。能力有限,只能写出这样的文章,如果有错误的地方,还烦请给我指出,以免误导他人,同时欢迎留言交流。

原创粉丝点击