Java(Spring01)
参考视频:Spring5最新完整教程IDEA版通俗易懂(狂神)
1. Spring
1.1 简介
- Spring:春天 -----> 给软件行业带来春天。
- 2002,首次推出了Spring框架的雏形:interface21框架。
- Spring框架即以interface21框架为基础,经过重新设计,并不断丰富其内涵,于2004年3月24日,发布了1.0正式版。
- Rod Johnson,Spring Framework创始人,著名作者。很难想象Rod Johnson的学历,真的让好多人大吃一惊,他是悉尼大学的博士,然而他的专业不是计算机,而是音乐学。
- spring理念:使现有的技术更加容易使用,本身是一个大杂烩,整合了现有的技术框架!
- SSH:Structs + Spring + Hibernate
- SSM:SpringMVC + Spring + Mybatis
- 官网:
- https://spring.io/projects/spring-framework#learn
- https://docs.spring.io/spring-framework/docs/current/reference/html/
- 官方下载地址:
- https://docs.spring.io/spring-framework/docs/4.3.9.RELEASE/spring-framework-reference/html/
- 点击
Distribution Zip Files
- 点击
http://repo.spring.io/release/org/springframework/spring
- GitHub地址:
- https://github.com/spring-projects/spring-framework
- 中文文档:
- https://www.docs4dev.com/docs/zh/spring-framework/5.1.3.RELEASE/reference/
- maven依赖
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
1.2 优点
- Spring是一个开源的免费的框架(容器)
- Spring是一个轻量级的,非侵入式的框架
- 控制反转(IOC),面向切面编程(AOP)
- 支持事务的处理,对框架整合的支持
- 总结:Spring是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架。
1.3 组成
1.4 拓展
- 在Spring的官网有这个介绍:现代化的Java开发,说白了就是,基于Spring的开发!
- Spring Boot
- 一个快速开发的脚手架。
- 基于SpringBoot可以快速地开发单个微服务。
- 约定大于配置。
- Spring Cloud
- SpringCloud是基于SpringBoot实现的。
- 现在大多数公司都在使用SpringBoot进行快速开发,学习SpringBoot的前提,必须要完全掌握Spring以及SpringMVC!承上启下的作用!
- 弊端: 发展了太久之后,违背了最初的理念!配置十分繁琐,人称“配置地狱”。
2. IOC理论推导
- UserDao 接口
public interface UserDao {
void getUser();
}
- UserDaoImpl 实现类
public class UserDaoImpl implements UserDao{
@Override
public void getUser() {
System.out.println("默认获取用户的数据");
}
}
- UserService 业务接口
public interface UserService {
void getUser();
}
- UserServiceImpl 业务实现类
- 被用户控制
public class UserServiceImpl implements UserService{
private UserDao userDao = new UserDaoOracleImpl();//随用户需求改动
@Override
public void getUser() {
userDao.getUser();
}
}
- 控制反转
public class UserServiceImpl implements UserService{
private UserDao userDao;
//利用set进行动态实现值的注入!
public void setUserDao(UserDao userDao) {
this.userDao = userDao;//用户要什么自己挑了传过来就行
}
@Override
public void getUser() {
userDao.getUser();
}
}
- 在我们之前的业务中,用户的需求可能会影响我们原来的代码,我们需要根据用户的需求去修改原代码!如果程序代码量十分大,修改一次的成本代价十分昂贵!
- 我们用一个Set接口实现。已经发生了革命性的变化!
- UserServiceImpl
private UserDao userDao;
//利用set进行动态实现值的注入!
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
- 之前,程序是主动创建对象!控制权在程序猿手上!
- 使用了set注入后,程序不再具有主动性,而是变成了被动地接受对象!
- 这种思想,从本质上解决了问题,我们程序猿不用再去管理对象的创建了。系统的耦合性大大降低,可以更加专注在业务的实现上!这就是IOC的原型!
IOC本质
- 控制反转loC(Inversion of Control),是一种设计思想,Dl(依赖注入)是实现loC的一种方法,也有人认为DI只是loC的另一种说法。没有loC的程序中,我们使用面向对象编程,对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,个人认为所谓控制反转就是:获得依赖对象的方式反转了。
- 采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。
- 控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是loC容器,其实现方法是依赖注入(Dependency Injection, DI)。
3. HelloSpring
- 先添加一个依赖
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.0.RELEASE</version>
</dependency>
</dependencies>
- Hello实体类
- 只有set、get方法(和一个toSting方法),没有有参构造方法!(但无参构造是默认存在的…)
package com.zach.pojo;
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 + '\'' +
'}';
}
}
- 在resources中添加文件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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--使用Spring来创建对象,在Spring中这些都成为Bean
类型 变量名 = new 类型();
Bean = 对象 new Hello();
id = 变量名
class = new的对象
property相当于给对象中的属性设置一个值
-->
<bean id="hello" class="com.zach.pojo.Hello">
<property name="str" value="Spring"/>
</bean>
</beans>
- MyTest
import com.zach.pojo.Hello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
// 获取Spring的上下文对象
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
// 我们的对象现在都在Spring中管理了,我们要使用,直接去里面取出来就可以了。
Hello hello = (Hello) context.getBean("hello");
System.out.println(hello.toString());
}
}
- 思考问题:
- Hello 对象是谁创建的 ?
- hello 对象是由 Spring创建 的
- Hello 对象的属性是怎么设置的 ?
- hello 对象的属性是由 Spring容器 设置的
- Hello 对象是谁创建的 ?
- 这个过程就叫 控制反转:
- 控制:谁在控制对象的创建,传统的应用程序的对象是由程序本身控制创建的,使用spring后, 对象由spring来创建 。
- 反转:程序本身不创建对象,而变成被动地接收对象。
- 依赖注入: 就是利用set方法来进行注入的.
- IOC是一种编程思想,由主动地编程变成了被动地接收。
- 尝试通过newClassPathXmlApplicationContext去浏览一下底层源码。(目前先不看了)
- 修改一下上一个的Module:spring-01-ioc1
- 在resources新增一个spring配置文件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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="mysqlImpl" class="com.zach.dao.UserDaoMysqlImpl"/>
<bean id="oracleImpl" class="com.zach.dao.UserDaoOracleImpl"/>
<bean id="sqlserverImpl" class="com.zach.dao.UserDaoSqlserverImpl"/>
<bean id="UserServiceImpl" class="com.zach.service.UserServiceImpl">
<!--ref:引入Spring容器中创建好的对象-->
<!--value:具体的值,基本数据类型-->
<property name="userDao" ref="sqlserverImpl"/>
</bean>
</beans>
- MyTest
import com.zach.dao.UserDaoImpl;
import com.zach.dao.UserDaoMysqlImpl;
import com.zach.dao.UserDaoOracleImpl;
import com.zach.dao.UserDaoSqlserverImpl;
import com.zach.service.UserServiceImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MyTest {
public static void main(String[] args) {
//获取ApplicationContext:拿到Spring的容器
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//容器在手,天下我有,需要什么,get什么!
UserServiceImpl userService = (UserServiceImpl) context.getBean("UserServiceImpl");
userService.getUser();
}
}
- 现如今,我们彻底不用再程序中去改动了,要实现不同的操作,只需要在xml配置文件中进行修改,所谓的loC,一句话搞定: 对象由Spring来创建,管理,装配!
4. IOC创建对象的方式
- 使用无参构造创建对象,默认!
package com.zach.pojo;
public class User {
private String name;
public User() {
System.out.println("User的无参构造!");
}//只留下有参构造,beans.xml的class会报错:No matching constructor found in class 'User'
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void show(){
System.out.println("name = "+name);
}
}
<!--当使用默认的无参构造时-->
<bean id="user" class="com.zach.pojo.User">
<property name="name" value="张天道"/>
</bean>
public class MyTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
User user = (User) context.getBean("user");
user.show();
}
}
- 假设我们要使用有参构造创建
- 下标赋值
<!--第一种:通过下标赋值 匹配-->
<bean id="user" class="com.zach.pojo.User">
<constructor-arg index="0" value="张酬勤"/>
</bean>
- 类型赋值
<!--第二种:通过参数赋值 匹配。但不建议使用,通常由多个同类型参数...-->
<bean id="user" class="com.zach.pojo.User">
<constructor-arg type="java.lang.String" value="天道酬勤"/>
</bean>
- 参数名
<!--第三种:直接通过参数名来设置-->
<bean id="user" class="com.zach.pojo.User">
<constructor-arg name="name" value="张天道&张酬勤"/>
</bean>
- 总结:在配置文件加载的时候,容器中管理的对象就已经初始化了!
5. Spring配置
5.1 别名
<!--别名:如果添加了别名,那我们同时也可以通过别名获取该对象了-->
<alias name="userT" alias="userAlias"/>
5.2 Bean的配置
<!--
id:bean的唯一标识符,也就是相当于我们学的对象名
class:bean对象所对应的全限定名:包名 + 类名
name:也是别名,但name更高级,可以同时取多个别名,可以用多种符号分隔
-->
<bean id="userT" class="com.zach.pojo.UserT" name="userAliasAlso,userAliasToo userZaiXia;userZhang">
<property name="name" value="在下张别名"/>
</bean>
5.3 import
- 这个import,一般在团队开发中使用,它可以将多个配置文件 导入 ,并且实现 合并 为一个。
- 假设,目前项目中有多个人在开发,这三个人复制不同的开发,不同的类需要注册在不同的bean中,我们可以利用import将所有人的beans.xml和合并为一个总的。
- 张三的
- 李四的
- 王五的
- applicationContext.xml(合并到此)
<import resource="beans.xml"/>
<import resource="beans2.xml"/>
<import resource="beans3.xml"/>
- 使用的时候,直接使用总的配置applicationContext.xml就可以了。
6. 依赖注入(DI)
6.1 构造器注入
- 前面已经说了(?)
6.2 Set方式注入【重点】
- 依赖注入:Ser注入!
- 依赖:bean对象的创建依赖于容器
- 注入:bean对象中的所有属性,由容器来注入
- 环境搭建:
- 复杂类型
package com.zach.pojo;
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 + '\'' +
'}';
}
}
- 真实测试对象
package com.zach.pojo;
import java.util.*;
public class Student {
private String name;//通过value能赋值
private Address address;//通过ref能赋值
private String[] books;
private List<String> hobbies;
private Map<String,String> card;
private Set<String> games;
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> getHobbies() {
return hobbies;
}
public void setHobbies(List<String> hobbies) {
this.hobbies = hobbies;
}
public Map<String, String> getCard() {
return card;
}
public void setCard(Map<String, String> card) {
this.card = card;
}
public Set<String> getGames() {
return games;
}
public void setGames(Set<String> games) {
this.games = games;
}
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{" +
"\nname='" + name + '\'' +
", \naddress=" + address.toString() +
", \nbooks=" + Arrays.toString(books) +
", \nhobbies=" + hobbies +
", \ncard=" + card +
", \ngames=" + games +
", \nwife='" + wife + '\'' +
", \ninfo=" + info +
'}';
}
}
- 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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="student" class="com.zach.pojo.Student">
<!--第一种:普通值注入,使用value-->
<property name="name" value="张天道"/>
</bean>
</beans>
- 测试类MyTest
import com.zach.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 student = (Student) context.getBean("student");
System.out.println(student.toString());
}
}
//Student{name='张天道',
// address=null, books=null, hobbies=null,
// card=null, games=null, wife='null', info=null}
- 完善注入信息
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="address" class="com.zach.pojo.Address">
<property name="address" value="天山or蜀山"/>
</bean>
<bean id="student" class="com.zach.pojo.Student">
<!--第一种:普通值注入,使用value-->
<property name="name" value="张天道"/>
<!--第二种:Bean注入,使用ref-->
<property name="address" ref="address"/>
<!--数组注入,使用array,value-->
<property name="books">
<array>
<value>《红楼梦》</value>
<value>《西游记》</value>
<value>《水浒传》</value>
<value>《三国演义》</value>
</array>
</property>
<!--List注入,使用list,value-->
<property name="hobbies">
<list>
<value>吃</value>
<value>喝</value>
<value>拉</value>
<value>撒</value>
<value>睡</value>
<value>写bug</value>
</list>
</property>
<!--Map注入,使用map,entry-->
<property name="card">
<map>
<entry key="身份证" value="000000199809250000"/>
<entry key="银行卡" value="6222620000000000407"/>
</map>
</property>
<!--Set注入,使用set,value-->
<property name="games">
<set>
<value>王者荣耀</value>
<value>绝地求生</value>
<value>炉石传说</value>
<value>守望先锋</value>
<value>OW</value>
</set>
</property>
<!--null注入,使用null-->
<property name="wife">
<null/>
</property>
<!--Properties注入,使用props-->
<property name="info">
<props>
<prop key="学号">2016022318</prop>
<prop key="姓名">张天道</prop>
<prop key="性别">男</prop>
<prop key="driver">driver</prop>
<prop key="url">url</prop>
<prop key="username">root</prop>
<prop key="password">123456</prop>
</props>
</property>
</bean>
</beans>
- 输出:(只有info的顺序乱了,不知为何)
Student{
name='张天道',
address=Address{address='天山or蜀山'},
books=[《红楼梦》, 《西游记》, 《水浒传》, 《三国演义》],
hobbies=[吃, 喝, 拉, 撒, 睡, 写bug],
card={身份证=000000199809250000, 银行卡=6222620000000000407},
games=[王者荣耀, 绝地求生, 炉石传说, 守望先锋, OW],
wife='null',
info={学号=2016022318, 性别=男, password=123456, url=url, driver=driver, 姓名=张天道, username=root}}
6.3 拓展方式注入
- 我们可以使用p命名空间和c命名空间进行注入
- 官方解释:
- 需要导入一下两段:
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
- 使用:
<?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"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--p命名空间注入,可以直接注入属性的值:property-->
<bean id="user" class="com.zach.pojo.User" p:name="张天道" p:age="28"/>
<!--c命名空间注入,是通过构造器注入属性的值:construct-args-->
<bean id="user2" class="com.zach.pojo.User" c:name="张酬勤" c:age="18"/>
</beans>
- 测试:
@Test
public void test2(){
ApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml");
User user = context.getBean("user", User.class);
System.out.println(user.toString());
}
@Test
public void test3(){
ApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml");
User user = context.getBean("user2", User.class);
System.out.println(user.toString());
}
- 注意点:p和c命名空间不能直接使用,需要导入上面提到的xml约束
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
6.4 bean的作用域
- 单例模式(Spring默认机制,不写就是单例)
- 每次从容器中get的时候,都会使用同一个对象
<bean id="user2" class="com.zach.pojo.User" c:name="张酬勤" c:age="18" scope="singleton"/>
- 单线程一般用单例,性能高,但也可能出现并发问题(延迟、输出不一致…)。
- 原型模式:
- 每次从容器中get的时候,都会产生一个新对象
<bean id="user2" class="com.zach.pojo.User" c:name="张酬勤" c:age="18" scope="prototype"/>
- 多线程一般用原型,性能低(浪费资源)。
- 其余的request、session、application,这些只能在web开发中使用到。
7. Bean的自动装配
- 自动装配是Spring满足bean依赖的一种方式。
- Spring会在上下文中自动寻找,并自动给bean装配属性。
- 在Spring中有三种装配的方式:
- 在xml中显式地配置(上面的)
- 在Java中显式地配置(未遇到的)
- 隐式地自动装配bean【重要】
7.1 测试
- 环境搭建:一人三宠物。
package com.zach.pojo;
public class Person {
private String name;
private Cat cat;
private Dog dog;
private Fox fox;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Cat getCat() {
return cat;
}
public void setCat(Cat cat) {
this.cat = cat;
}
public Dog getDog() {
return dog;
}
public void setDog(Dog dog) {
this.dog = dog;
}
public Fox getFox() {
return fox;
}
public void setFox(Fox fox) {
this.fox = fox;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", cat=" + cat +
", dog=" + dog +
", fox=" + fox +
'}';
}
}
package com.zach.pojo;
public class Cat {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Cat{" +
"name='" + name + '\'' +
'}';
}
public void say(){
System.out.println("喵喵喵~ or meow~ ...");
}
}
package com.zach.pojo;
public class Dog {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
'}';
}
public void say(){
System.out.println("汪汪汪~ or ruff~ ...");
}
}
package com.zach.pojo;
public class Fox {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Fox{" +
"name='" + name + '\'' +
'}';
}
public void say(){
System.out.println(
"Ring-ding-ding-ding-dingeringeding or " +
"Wa-pa-pa-pa-pa-pa-pow or " +
"Hatee-hatee-hatee-ho...");
}
}
<?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
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="cat" class="com.zach.pojo.Cat">
<property name="name" value="小炎"/>
</bean>
<bean id="dog" class="com.zach.pojo.Dog">
<property name="name" value="木木云力"/>
</bean>
<bean id="fox" class="com.zach.pojo.Fox">
<property name="name" value="貂爷"/>
</bean>
<bean id="person" class="com.zach.pojo.Person">
<property name="name" value="林动"/>
<property name="cat" ref="cat"/>
<property name="dog" ref="dog"/>
<property name="fox" ref="fox"/>
</bean>
</beans>
@Test
public void test1(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Person person = context.getBean("person", Person.class);
System.out.println(person.toString());
person.getCat().say();
person.getDog().say();
person.getFox().say();
}
7.2 ByName自动装配
- autowire=“byName”
<!--byName:会自动在容器上下文中查找,和自己对象set方法后面的值对应的bean id!-->
<bean id="person" class="com.zach.pojo.Person" autowire="byName">
<property name="name" value="林动"/>
</bean>
7.3 ByType自动装配
- autowire=“byType”
<bean id="dog" class="com.zach.pojo.Dog">
<property name="name" value="木木云力"/>
</bean>
<bean class="com.zach.pojo.Fox">
<property name="name" value="貂爷"/>
</bean>
<!--byName:会自动在容器上下文中查找,和自己对象set方法后面的值对应的bean id!-->
<!--byType:会自动在容器上下文中查找,和自己对象属性类型相同的bean!所以上面不写id="fox"也可以-->
<bean id="person" class="com.zach.pojo.Person" autowire="byType">
<property name="name" value="林动"/>
</bean>
- 小结:
- byName的时候,需要保证所有bean的id唯一,并且这个bean需要和自动注入的属性的set方法的值一致。
- byType的时候,需要保证所有的bean的class唯一,并且这个bean需要和自动注入的属性的类型一致。
7.4 使用注解实现自动装配
- jdk1.5起支持注解,spring2.5起支持注解。
- The introduction of annotation-based configuration raised the question of whether this approach is “better” than XML.
- 基于注释的配置的引入提出了这种方法是否比 XML“更好”的问题。
- 注解使用须知:
- 导入约束:context约束
- 配置注解的支持:
<context:annotation-config/>
<?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/>
</beans>
- @Autowired注解
- 直接在属性上使用即可,也可以在set方法上使用。
- 使用Autowired,我们可以不写set方法,前提是这个自动装配的属性在IOC(Spring)容器中存在,且符合类型byType
- 科普:
@Nullable //当字段标记了这个注解,说明这个字段可以为null。(但没有测试成功)
public @interface Autowired {
boolean required() default true;
}
- 测试代码
- Person
public class Person {
private String name;
//如果显式地定义了Autowired的required属性为false,说明这个对象可以为null,否则不允许为空。
@Autowired
private Cat cat;
@Autowired
private Dog dog;
@Autowired
private Fox fox;
- 如果@Autowired自动装配的环境比较复杂,自动装配无法通过一个注解【@Autowired】完成的时候,我们可以使用【@Qualifier(value=“”)】去配合@Autowired一起使用,指定一个唯一的bean对象注入。
public class Person {
private String name;
@Autowired
private Cat cat;
@Autowired
private Dog dog;
@Autowired
@Qualifier(value = "fox")
private Fox fox;
- @Resource注解 ,Java的注解
public class Person {
private String name;
@Autowired
private Cat cat;
@Autowired
@Resource(name = "dog")
private Dog dog;
@Autowired
@Qualifier(value = "fox")
private Fox fox;
- 小结:
- @Resource 和 @Autowired 的区别:
- 都是用来自动装配的,都可以放在属性字段上。(都常用)
- @Autowired 默认通过byType 的方式实现,而且必须要求这个对象存在!(但是如果不能唯一自动装配上属性,则需要通过@Qualifier(value=“”)装配名字)
- @Resource 默认则通过byName的方式实现,但是如果找不到名字,还能通过byType实现!两种都找不到则报错。
- 执行顺序不同:@Autowired 默认通过byType的方式实现,@Resource 默认通过byName的方式实现。
- @Resource 和 @Autowired 的区别:
8. 使用注解开发
- 在Spring4之后,要使用注解开发,必须要保证aop的包导入了。
- 使用注解需要导入context约束,增加注解的支持。
<?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:component-scan base-package="com.zach.pojo"/>
<!--开启注解支持-->
<context:annotation-config/>
</beans>
8.1 bean
8.2 属性如何注入
//等价于<bean id="user" class="com.zach.pojo.User"/>
//@Component组件
@Component
public class User {
public String name;
//相当于<property name="name" value="张天道"/>
@Value("张天道")
public void setName(String name) {
this.name = name;
}
}
8.3 衍生的注解
- @Component 有几个衍生注解,我们在web开发中,会按照mvc三层架构分层!
- dao【@Repository】
- service【@Service】
- controller【@Controller】
- 这四个注解的功能都一样的,都是代表将某个类注册到Spring中,装配Bean
8.4 自动装配配置
- @Autowired
- 自动装配,通过类型或名字。
- 先通过类型,如果不能唯一自动装配上属性,则需要通过@Qualifier(value=“”)装配名字。
- @Nullable
- 字段标记了这个注解,说明该字段可为null
- @Resource
- 自动装配,通过名字或类型。
- 先通过byName,但是如果找不到名字,还能通过byType实现!
8.5 作用域
//等价于<bean id="user" class="com.zach.pojo.User"/>
//@Component组件
@Component
@Scope("singleton")
public class User {
public String name;
//相当于<property name="name" value="张天道"/>
@Value("张天道")
public void setName(String name) {
this.name = name;
}
}
8.6 小结
- xml 与 注解:
- xml:更加万能,适用于任何场合!维护简单方便。
- 注解:不是自己的类使用不了,维护相对复杂。
- xml 与 注解的最佳实践:
- xml:用来管理bean
- 注解:只负责完成属性的注入
- 在使用过程中,主要注意一个问题:让注解生效的必要条件:开启注解支持!
<!--指定要扫描的包,在这个包下的注解就会生效-->
<context:component-scan base-package="com.zach"/>
<!--开启注解支持-->
<context:annotation-config/>
9. 使用Java的方式配置Spring
-
我们现在完全可以不用Spring的xml配置,而全权交给Java来做!
-
JavaConfig是Spring的一个子项目,在Spring4之后,它成为了一个核心功能。
-
User(实体类)
package com.zach.pojo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
//该注解含义:将该类注册到容器中,由Spring接管。
@Component
public class User {
@Value("张天道")//注入属性的值,这里是name的值
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
'}';
}
}
- ZachConfig(配置文件(配置类))
package com.zach.config;
import com.zach.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
//该注解含义:将该类注册到容器中,由Spring接管,因为它本身也是被加了注解@Component了
//所以,加了注解@Configuration后,代表这是一个配置类,和之前的beans.xml类似。
@Configuration
@ComponentScan("com.zach")
@Import(ZachConfig2.class)
public class ZachConfig {
//注册一个bean,就相当于之前写的bean标签
//该方法的名字,就相当于bean标签的id属性
//该方法的返回值,就相当于bean标签的class属性
@Bean
public User user(){
return new User();//这里返回的就是要注入到bean的对象
}
}
- MyTest(测试类)
import com.zach.config.ZachConfig;
import com.zach.pojo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class MyTest {
public static void main(String[] args) {
//如果完全使用了配置类方式去做,我们就只能通过AnnotationConfigApplicationContext上下文来获取容器,
//通过配置类的class对象加载!
ApplicationContext context = new AnnotationConfigApplicationContext(ZachConfig.class);
User user = context.getBean("user", User.class);
System.out.println(user.getName());
}
}
- 这种纯Java的配置方式,在SpringBoot中随处可见!