文章目录
1. Spring5
1.1 Spring5 概述
Spring 是轻量级的开源的JavaEE框架。
Spring 可以解决企业应用开发的复杂性。
Spring 有两个核心部分: IOC(Inversion of Control, 控制反转) 和 AOP( Aspect Oriented Programming , 面向切面编程)
Spring是分层的Java SE/EE应用 full-stack 轻量级开源框架,以IOC和AOP为内核。
IOC(Inversion of Control, 控制反转) : 把创建对象过程交给spring进行。
AOP(Aspect Oriented Programming , 面向切面编程):不修改源代码进行功能增强。
Spring的特点:
- 方便解耦,简化开发(将对象间的依赖关系交由Spring进行控制,避免过度耦合)。
- AOP编程支持。
- 方便程序的测试。
- 方便集成整合各种优秀框架(Struts,Hibemate等)。
- 方便进行事务操作(Spring ,通过声明式方式灵活的进行事务管理)。
- 降低Java API的开发难度。
1.2 其他框架
SSH框架 : Struct2 + Spring + Hibernate(自动)
SSM框架 : SpringMVC + Spring + Mybatis(半自动)
学习顺序:
Spring Boot
- 一个快速开发的脚手架。
- 基于SpringBoot可以快速的开发单个微服务。
Spring Cloud
- Spring Cloud 是基于Spring Boot实现的,用来管理它的。
2. Spring5 的相关jar包下载
Spring5下载相关jar包:https://spring.io/projects/spring-framework#learn
注意GA 和 snapshot的区别:
General Availability,正式发布的版本。
想要下载其他版本的可以访问该地址:
https://repo.spring.io/ui/native/release/org/springframework/spring
Spring大体上的一个模块框架:
Core Container:核心容器 ,这个是最基础要掌握的,上面的操作都是基于核心容器来实现的。
3. Spring5 IOC容器
3.1 为什么要用IOC?
做程序讲究高内聚,低耦合。
一般我们的声明对象调用方法,都是new 对象,调用该对象的方法,但是如果我们修改了对象方法的名字,那么一下子啊就要改所有调用该方法的对象,这样耦合度太高了。
对于上面这种情况可以通过工厂模式来达到一个解耦效果:(通过UserFactory,大大降低了UserService和UserDao直接的耦合。)
但是,工厂模式下的耦合度还不是最低的,还可以通过IOC来实现这降低耦合!!
3.2 什么是 IOC?
IOC控制反转,把对象创建和对象之间的调用过程,交给Spring进行管理。
没有IOC冲虚,一系列的对象创建都是由程序自己完成,控制反转后将对象的创建转移给第三方,也就是获得依赖对象的方式反转了。
使用IOC目的:为了耦合度降低。
IOC的底层原理由三个部分组成:
- xml解析。
- 工厂模式。
- 反射
也就是说学spring之前,java的工厂模式和java反射都要知道!
IOC总结:
采用xml方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。
控制反转是一种通过描述(XML或注解) 并通过第三方去生产或获取特定的对象方式。在Spring中实现控制反转的是IOC容器,其实现方法是依赖注入(Dependency Injection , ID)
3.3 IOC 接口
IOC思想基于IOC容器完成,IOC容器底层就是对象工厂。
spring提供了实现IOC容器的两种方式:(也就是两个接口)
- BeanFactory接口:该接口是IOC容器最基本的实现方式,是spring内部自带的接口,不提供开发人员进行使用。
- ApplicationContext接口:它是BeanFactory接口的子接口,提供了更多更强大的功能,一般是开发人员使用的。
上面两个都能实现IOC容器。
4. Spring 实例
所谓的IOC就是:对象由Spring来创建,管理,装配。
创建一个maven项目,在pom.xml中导入spring的相关依赖:
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.3.9</version>
</dependency>
</dependencies>
如下案例:
创建一个beans的xml文件:
<?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来创建对象,在Spring中这些都称作为Bean-->
<!--反转:程序本身不创建对象,而变成被动的接受对象。-->
<bean id="hello" class="com.itholmes.pojo.Hello">
<!--property属性作用就是为str设置一个值。-->
<!--依赖注入:就是利用set方法进行注入的,也就是这里的str必须在自己的类中有set方法,来修改它才行!!!-->
<property name="str" value="Spring"/>
<!--
property中,ref属性和value属性不同:
ref:引用spring容器中创建好的对象。
value:具体的值,基本数据类型。
-->
</bean>
</beans>
在maven中的main/java中创建hello.java类
package com.itholmes.pojo;
/*
概述:
@Date:Create in 9:36 2021/12/27
*/
public class Hello {
private String str;
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
@Override
public String toString() {
return "Hello{" +
"str='" + str + '\'' +
'}';
}
}
在maven的test/java中测试能否通过xml文件创建管理类:
/*
概述:
@Date:Create in 9:48 2021/12/27
*/
import com.itholmes.pojo.Hello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Mytest {
public static void main(String[] args) {
//获取spring的上下文对象context,也就是获取ApplicationContext:拿到Spring的容器。
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//我们的对象现在都在Spring中管理了,我们要使用,直接去里面取出来调用就可以了。
Hello hello = (Hello) context.getBean("hello");
System.out.println(hello.toString());
}
}
bean属性ref的使用:
注意:idea提示创建上下文参数
上面的意思可以理解为创建一个新的程序上下文参数,配置该文件到spring项目中去。
我们可以在project structure中看到applicationcontext的内容:
完成上面操作,我们在类中可以看到相关的标签已经导入进来:
5. Spring IOC创建对象的方式
5.1 使用无参构造器创建对象(默认)
IOC在配置xml文件控制反转时,创建对象也是分无参数和有参数的,默认的就是无参数构造器。
5.2 有参数构造器创建对象
方式一,index下标的方式:
<!--第一种:使用index下标赋值。-->
<bean id="user" class="com.itholmes.pojo.User">
<constructor-arg index="0" value="张三"/> <!--第一个参数-->
<constructor-arg index="1" value="18"/> <!--第二个参数-->
</bean>
方式二:通过使用类型创建,不建议使用!
<!--第二种:通过使用类型创建,不建议使用!-->
<bean id="user" class="com.itholmes.pojo.User">
<!--注意基本类型可以直接用int,short等等,但是String引用类型必须写全,平时我们代码中直接写的String的也只是java.lang.String的别名而已。-->
<constructor-arg type="java.lang.String" value="张三"/>
<constructor-arg type="int" value="18"/>
</bean>
第三种:通过使用参数名和name属性来传递参数,建议使用。
<!--第三种:通过使用参数名和name属性来传递参数。-->
<bean id="user" class="com.itholmes.pojo.User">
<constructor-arg name="name" value="张三"/>
<constructor-arg name="age" value="18"/>
</bean>
我们平时说的spring容器就是下面的context:
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
总结:在配置文件加载的时候,容器中管理的对象就已经初始化了。
这句话意思不难理解,就是我们所有配置在beans中的内容,都将会在new ClassPathXmlApplicationContext(“beans”); 执行完后将beans中所有的配置的类对象,全部加载创建完毕。之后我们想调用谁就调用谁,也就是在一个容器当中想用谁就用谁。
6. Spring 配置
6.1 别名
alias别名:就是给user起了个别名,同样我们可以使用别名获取到这个对象。
<!--alias别名:就是给user起了个别名,同样我们可以使用别名获取到这个对象。-->
<alias name="user" alias="alias_user"/>
6.2 Bean标签 的配置属性
对于Bean标签的配置属性,基本的如下:
<!--
id: bean的唯一标识符,也就是对应对象名。
class: bean对象所对应的全限定名,全限定名就是包名加类名。
name: 这里的name是当前bean的别名,并且name可以取多个别名。(中间分隔,可以用空格,逗号,分号都可以进行分隔效果。)
-->
<bean id="AddrT" class="com.itholmes.pojo.AddrT" name="T,T2,abcT3">
</bean>
6.3 import标签
import标签,一般用于团队开发使用,他可以将多个配置文件,导入合并为一个。
import标签功能很强大,如果遇到相同的内容,就会覆盖一起,别名也是一样的。
7. 依赖注入
7.1 什么是依赖注入?
在Spring中实现控制反转的是IOC容器,其实现方法是依赖注入(Dependency Injection , ID)
7.2 构造器注入
构造器,在第三节的Spring IOC创建对象的方式中已经说明。
7.3 Set方式注入(重点)
依赖注入:Set注入
在这解释一下为什么set注入,因为它必须要用到setXxx()方法因此这样命名。
- 依赖:bean对象的创建依赖于容器。
- 注入:bean对象中的所有属性,由容器来注入!
set注入效果如下:
<?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="addr_id" class="com.itholmes.pojo.Address">
<property name="address" value="上海"/>
</bean>
<bean id="student" class="com.itholmes.pojo.Student">
<!--name属性指向的是类中的变量属性名。-->
<!--第一种,普通值注入:value属性-->
<property name="name" value="张三"/>
<!--第二种,Bean值注入:ref属性-->
<property name="address" ref="addr_id"/>
<!--第三种,数组注入:array标签-->
<property name="books">
<array>
<value>三国演义</value>
<value>水浒传</value>
<value>红楼梦</value>
<value>西游记</value>
</array>
</property>
<!--第四种,list集合注入:list标签-->
<property name="hobbys">
<list>
<value>听歌</value>
<value>玩游戏</value>
<value>打篮球</value>
</list>
</property>
<!--第五种,map集合注入:map标签和entry标签使用-->
<property name="card">
<map>
<entry key="学号" value="123"/>
<entry key="姓名" value="itholmes"/>
</map>
</property>
<!--第六种,Set集合注入:set标签-->
<property name="game">
<set>
<value>123</value>
<value>456</value>
<value>789</value>
</set>
</property>
<!--第七种,null值注入:null-->
<property name="wife">
<null/>
</property>
<!--空字符串的注入如下:-->
<!--<property name="wife" value=""/>-->
<!--第八种,Properties注入:props标签和prop标签-->
<property name="info">
<props>
<prop key="username">root</prop>
<prop key="password">root</prop>
<prop key="url">jdbc:mysql://localhost:3306/</prop>
<prop key="driver">com.mysql.jdbc.Driver</prop>
</props>
</property>
</bean>
</beans>
student类:
package com.itholmes.pojo;
/*
概述:
@Date:Create in 9:12 2021/12/28
*/
import java.util.*;
public class Student {
private String name;
private Address address;
private String[] books;
private List<String> hobbys;
private Map<String,String> card;
private Set<String> game;
private String wife;
private Properties info;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
public String[] getBooks() {
return books;
}
public void setBooks(String[] books) {
this.books = books;
}
public List<String> getHobbys() {
return hobbys;
}
public void setHobbys(List<String> hobbys) {
this.hobbys = hobbys;
}
public Map<String, String> getCard() {
return card;
}
public void setCard(Map<String, String> card) {
this.card = card;
}
public Set<String> getGame() {
return game;
}
public void setGame(Set<String> game) {
this.game = game;
}
public String getWife() {
return wife;
}
public void setWife(String wife) {
this.wife = wife;
}
public Properties getInfo() {
return info;
}
public void setInfo(Properties info) {
this.info = info;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", address=" + address.toString() +
", books=" + Arrays.toString(books) +
", hobbys=" + hobbys +
", card=" + card +
", game=" + game +
", wife='" + wife + '\'' +
", info=" + info +
'}';
}
}
Address类:
package com.itholmes.pojo;
/*
概述:
@Date:Create in 9:16 2021/12/28
*/
public class Address {
private String address;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@Override
public String toString() {
return "Address{" +
"address='" + address + '\'' +
'}';
}
}
测试类MyTest:
/*
概述:
@Date:Create in 9:28 2021/12/28
*/
import com.itholmes.pojo.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Student s = (Student) context.getBean("student");
System.out.println(s.toString());
//Student{name='张三', address=Address{address='上海'}, books=[三国演义, 水浒传, 红楼梦, 西游记], hobbys=[听歌, 玩游戏, 打篮球], card={学号=123, 姓名=itholmes}, game=[123, 456, 789], wife='null', info={password=root, url=jdbc:mysql://localhost:3306/, driver=com.mysql.jdbc.Driver, username=root}}
}
}
不同的类型,通过不同的方式进行注入!
7.4 p命名 和 c命名空间注入
7.4.1 概述
官方文档:https://docs.spring.io/spring-framework/docs/current/reference/html/core.html
p命名和c命名如下:
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
7.4.2 p-namespace p命名空间
p命名空间注入,可以直接注入属性的值。(这里的p就是property属性的意思
userbeans.xml文件:
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--p命名空间注入,可以直接注入属性的值。(这里的p就是property属性的意思。)-->
<bean id="user" class="com.itholmes.pojo.User" p:name="张三" p:age="18"/>
</beans>
User.java类:
package com.itholmes.pojo;
/*
概述:
@Date:Create in 10:11 2021/12/28
*/
public class User {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
MyTest02.java测试类:
/*
概述:
@Date:Create in 10:51 2021/12/28
*/
import com.itholmes.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest02 {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml");
User user = context.getBean("user",User.class); //在后面添加上了User.class类型后,就不用每次都强转了。
System.out.println(user.toString());
//User{name='张三', age=18}
}
}
这里我们可以通过使用测试类验证,p命名是否注入成功。
7.4.3 c-namespace c命名空间
这里就是传递构造器的内容了,注意如果我们添加了有参构造器,那么无参构造器也要添加,不然前面的默认无参构造器的bean会报错!
c命名空间的xml文件:
<?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:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--c命名空间注入,可以通过构造器注入。(这里的c就是constructor构造器的意思。)-->
<bean id="user2" class="com.itholmes.pojo.User" c:age="18" c:name="itholmes"/>
<!--注意这里仅仅只是调用了age和name也可以用index下标来表示,了解就好。-->
</beans>
User.java类(比起上添加了有参和无参构造器):
package com.itholmes.pojo;
/*
概述:
@Date:Create in 10:11 2021/12/28
*/
public class User {
private String name;
private int age;
public User() {
}
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
同样进行MyTest02.java测试:
/*
概述:
@Date:Create in 10:51 2021/12/28
*/
import com.itholmes.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest02 {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml");
User user = context.getBean("user2",User.class); //在后面添加上了User.class类型后,就不用每次都强转了。
System.out.println(user.toString());
//User{name='itholmes', age=18}
}
}
c命名空间就是设置有参构造器的,很容易理解。
注意:p命名和c命名空间不能直接使用,需要导入xml约束,所谓的约束就是下面的这段代码:
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
8. Bean 作用域(scopes)
8.1 官方的bean 6个作用域
在官方上面bean的作用域有六种:
我们写代码的原则就是能用单例就不会用多例,因为单例节省资源。一般用多例的情况都是不能使用单例的情况下才使用多例,如多线程的共享成员变量的问题。
8.2 singleton 单例模式(Spring 默认的模式)
singleton意思是单例。
Spring默认就是单例模式。
通过scope属性设置为singleton:
<bean id="user2" class="com.itholmes.pojo.User" c:age="18" c:name="itholmes" scope="singleton"/>
spring的bean设置为单例,开始默认就是单例的饿汉模式,就是在加载容器时就直接加载。
spring的bean设置为多例,就是多例的懒汉模式,什么时候需要,什么使用用的原则。
在spring中,单例是可以改成懒汉模式的!!需要设置懒加载。
8.3 prototype 原型模式
原型模式和我们认识的多例模式差不多。
scope属性值设置为prototype就可以了。
<bean id="user2" class="com.itholmes.pojo.User" c:age="18" c:name="itholmes" scope="prototype"/>
多线程一般使用原型模式,单线程一般使用单例模式,看情况使用。
MyTest02.java 测试类:
/*
概述:
@Date:Create in 10:51 2021/12/28
*/
import com.itholmes.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest02 {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml");
User user = context.getBean("user2",User.class); //在后面添加上了User.class类型后,就不用每次都强转了。
User user2 = context.getBean("user2",User.class); //在后面添加上了User.class类型后,就不用每次都强转了。
//原型模式就是不同的对象了。
System.out.println(user.hashCode()+","+user2.hashCode());
System.out.println(user == user2);
//1709366259,1335298403
//false
}
}
可以看到上面的结构无论是hashcode还是判断都是不同的对象。
也就是每次从容器中获得时,都会获得一个新对象。
8.4 request,session ,application
request,session ,application这些个只能在web开发中使用。
就是Servlet的三大域对象一样的。
- 设置为request:对象只能在一次请求内存活。
- 设置为session:对象只能在一次会话内存活。
- 设置为application:对象在项目开始到项目关闭存活。
9. Bean的生命周期 和 后置器
9.1 Bean的生命周期
初始化回调接口:
- org.springframework.beans.factory.InitializingBean 接口指定一个单一的方法(afterPropertiesSet方法)。
意思很简单,就是我们在spring配置bean对象,如果继承了上面的接口,在创建bean对象后,就会调用响应的实现方法来初始化。
销毁回调
- org.springframework.beans.factory.DisposableBean 接口指定一个单一的方法(destroy方法)
意思也很简单,实现了这个接口的bean对象,在被销毁的时候,就会调用destroy方法。
我们可以通过context.regitsterShutdownHook()方法(关闭容器),来查看bean的销毁,并且发现一个特点,就是bean不是伴随着容器的关闭而关闭,而是容器关闭后,直到项目关闭就走销毁,并且关闭。
bean的生命周期,销毁过程是regitsterShutdownHook()方法后,等程序结束后再销毁bean。
对于上面,我们更喜欢直接在xml文件中,配置初始化方法指定那个方法,销毁指定那个方法。
- 使用 init-method 属性来指定带有 void 无参数方法的名称。
- destroy-method 属性来指定带有 void 无参数方法的名称。
9.2 Bean的后置处理器
Bean 后置处理器允许在调用初始化方法前后对 Bean 进行额外的处理。
实现BeanPostProcessor接口的类,要实现以下的两个抽象方法 BeanPostProcessor.postProcessBeforeInitialization(Object, String) 和 BeanPostProcessor.postProcessAfterInitialization(Object, String)方法
注意:这里的bean,是操作当前xml文件的所有bean的初始化。
10. Bean 自动装配
10.1 Bean的装配方式
自动装配是Spring满足bean依赖的一种方式。
Spring会在上下文中自动寻找,并自动给bean装配属性。
Spring中有三种装配的方式:
- 在xml中显示的配置。(前面)
- 在java中显示配置。
- 隐式的自动装配bean。(重点!)
10.2 bean 隐式的自动装配(Autowired)
10.2.1 Autowired 属性
官方给的是:自动装配Autowired。
通过Autowired属性设定。
10.2.2 Autowired的 byName值
byName值:会自动在容器上下文中查找,和自己对象setXxx方法后面的Xxx值对应的beanid
<?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="cat" class="com.itholmes.pojo.Cat"/>
<bean id="dog" class="com.itholmes.pojo.Dog"/>
<!--
autowire属性:
byName值:会自动在容器上下文中查找,和自己对象setXxx方法后面的Xxx值对应的beanid。
-->
<bean id="people" class="com.itholmes.pojo.People" autowire="byName">
<!--People类中调用了上面的内容,这样我们就可以自动装配了,而不用设置property来手动设置。-->
</bean>
</beans>
弊端:必须和set后面的名字相同,也就是唯一才能自动装配到。
10.2.3 Autowired的 byType值
byType值:会自动在容器上下文中查找,和自己对象属性类型相同的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">
<bean id="cat" class="com.itholmes.pojo.Cat"/>
<bean id="dog" class="com.itholmes.pojo.Dog"/>
<!--
autowire属性:
byType值:会自动在容器上下文中查找,和自己对象属性类型相同的bean。
-->
<bean id="people" class="com.itholmes.pojo.People" autowire="byType">
</bean>
</beans>
弊端:type类型必须唯一,不然会直接报错的,同样就算设置的bean没有id,依然能够自动装配,因为是根据类型来的。。
11. Spring的注解 实现自动装配
注解仅仅是JDK1.5以上支持的版本,在Spring中2.5 版本就支持注解了。
使用注解前提:
- 导入约束。
- 配置注解的支持。
官方的注解配置如下:
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<!--
上面的xmlns:context="http://www.springframework.org/schema/context"要添加的命名空间也就是约束。
-->
</beans>
第一步,添加约束:
添加一个约束:
xmlns:context="http://www.springframework.org/schema/context"
两个约束的支持就是xsi:schemaLocation中的:
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
第二步,添加注解支持:
context:annotation-config,开启注解的支持。
<context:annotation-config\>
设置好上面的约束后,就可以在对象类中设置@Autowired注解:
(被注解注释的属性必须与xml文件中的bean的id属性相同)
@Autowired注解注意事项:
- 使用了@Autowired注解后,连set方法都是不需要的!
- @Autowired注解直接在属性上使用即可!也可以在setXxx方法上使用。
- 使用@Autowired我们可以不用编写setXxx方法了,前提是你这个自动装配的属性在IOC(Spring)容器中存在,且bean的id值名字必须相同!
@Nullable注解使用:
@Nullable 某个字段标记了这个注解,说明这个字段可以为null!
@Autowired注解源码如下:
public @interface Autowired {
boolean required() default true;
}
因此,它是有一个required属性的设置,设个属性和@Nullable注解差不多来定义能否为null的。
如果显示定义了Autowired的required属性为false,说明这个对象可以为null;定义为true,就不能为空!
@Autowired注解:
可以自动进行装配匹配xml文件中的bean效果,不用设置property属性了。但是如果有多个bean名字差不多,这是Autowired就会报错了!原因就是不确定找不到是哪一个。如下:
@Qualifier注解:
这个时候就需要@Qualifier(value=“xxx”)来指定xml配置文件中的bean属性了。
@Qualifier注解和@Autowired注解是一般成对出现的。
代码效果如下:
package com.itholmes.pojo;
/*
概述:
@Date:Create in 14:10 2021/12/28
*/
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.lang.Nullable;
public class People {
//如果显示定义了Autowired的required属性为false,说明这个对象可以为null;定义为true,就不能为空!。
@Autowired
@Qualifier(value = "cat222")
private Cat cat;
@Autowired
@Qualifier(value = "dog222")
private Dog dog;
private String name;
public People() {
}
//@Nullable注解:name为空也不会报错!
public People(String name) {
this.name = name;
}
public Cat getCat() {
return cat;
}
public Dog getDog() {
return dog;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "People{" +
"cat=" + cat +
", dog=" + dog +
", name='" + name + '\'' +
'}';
}
}
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!--开启注解的支持-->
<context:annotation-config/>
<bean id="cat111" class="com.itholmes.pojo.Cat"/>
<bean id="cat222" class="com.itholmes.pojo.Cat"/>
<bean id="dog111" class="com.itholmes.pojo.Dog"/>
<bean id="dog222" class="com.itholmes.pojo.Dog"/>
<bean id="people" class="com.itholmes.pojo.People"/>
</beans>
确定好前后对应即可。
12. java自带的注解 实现自动装配
@Resource注解:
同样,在没有多个bean的相同类型时,@Resource也是可以实现自动装配,name属性也可以指定bean的属性值id。
注意这个Resource注解是javax.annotation.Resource下的,不是spring的东西。
开发中,我们常用的就是@Autowired注解和@Resource注解实现,前者最多。
@Resource和@Autowired的区别:
- 都是用来自动装配的,都可以放在属性字段上。
- @Autowired通过byType的方式实现,如果设置了@Qualifier(value=“xxx”)则用byname实现,而且必须要求该对象bean存在!
- @Resource默认通过byname的方式实现,如果找不到名字,则通过byType实现,如果两个都找不到就会报错!。
- 执行顺序不同:@Autowired先是通过byType实现,@Resource先是通过byname实现
13. Spring 注解开发
13.1 四个注解的使用
上面说过的注解如下:
@Autowired:spring自动装配,配合@Qualifier(value=“xxx”)来使用。
@Nullable:字段标记了这个注释,说明这个字段可以为null。
@Resource:java自带的自动装配通过名字,类型。
在介绍一个@Component注解:
@Component:Component英文意思就是组件的意思。
这个注解相当于我们自定义的bean标签,例如:
<bean id="user" class="com.itholmes.dao.User"/>
注意使用@Component注解时,必须指定要扫描的包:
<context:component-scan base-package=“com.itholmes.dao”/>
换句话说,我们不用自己去xml文件定义对象bean标签了。
他还有一个@Value(“xxx”)注解可以给属性变量添加值,我们之前的@Autowired是给自己创建的引用实例类来自动装配的。
User.java类:
package com.itholmes.dao;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
//@Component英文意思就是组件的意思。
//等价于<bean id="user" class="com.itholmes.dao.User"/>
@Component
public class User {
//@Value等价于它:<property name="name" value="ithomes"/>
@Value("itholmes")
public String name;
//也可以注入到set方法上面
//@Value("itholmes")
public void setName(String name) {
this.name = name;
}
}
beans.xml如下:
<?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"
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.itholmes.dao"/>
<context:annotation-config/>
</beans>
测试类:
/*
概述:
@Date:Create in 10:13 2021/12/30
*/
import com.itholmes.dao.User;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = context.getBean("user", User.class);
System.out.println(user.name);
}
}
13.2 @Component的衍生注解
@Component有几个衍生注解,在web开发中,会按照mvc三层架构分层。
- dao层 : @Repository
- service层:@Service
- controller层:@Controller ,注意:@Controller是servlet和springmvc的结合体,是基于http协议的。
换句话说这四个注解的功能是相同的!都是代表某个类注入到Spring容器中,装配Bean。
注意,不要忘记扫描包的的声明!
13.5 @Value注解的使用
上面我们通过@Autowired注解来自动装配指定实例类的操作。
我们还可以通过@Value来给类中的属性变量设置值。
13.4 @Scope注解 作用域的使用
@Scope就是对应上面我们设定scope属性的注解,同样值常用的就是singleton单例模式,prototype原型模式。
Scope也就是作用域。
13.5 总结 xml和注解 的优劣
xml 与 注解:
- xml是万能的,适用于任何场合!维护起来简单方便。
- 注解是定义到类中,因此不是被自己注解的类是不能够使用的。而且维护起来相对复杂一些。
最佳方案如下:
- 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"
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.itholmes.dao"/>
<context:annotation-config/>
</beans>
14. 补充
14.1 获取bean的三种方式
获取bean的三种方式:
- bean的id。
- bean的类。
- bean的类的接口。
14.2 @Autowired注解自动装配常见的几个错误
一般碰到这个就是我们@autowired的对象,不确定是哪一个实现类了。
我们一般都是通过下面的方式来操作解决。
总结:
- @Autowired注解是根据类型找实现类,找到的实现类,再看他们的名称。如果有多个。就会报错。因此需要@Qualifier注解。
- 如果不指定@Service(“xxx”)的别名,默认就是首字母小写的类名,其他3个注解也一样。
@Autowired有一个required值设置为true就是必须要注入。
false就是注入不注入无所谓也不会报错,但是如果没有注入成功,调用其方法因为没有注入进来就会空指针异常。