spring自动装配
Spring 框架提供了一种机制,称为自动装配(Autowired),它允许 Spring 容器自动将依赖注入到 Bean 中,而无需显式地使用 XML 配置文件或构造函数注入。自动装配简化了依赖注入的过程,使得代码更加简洁和易于维护。
1 自动装配的基本概念
自动装配是指 Spring 容器自动为一个 Bean 的属性找到合适的依赖对象,并将其注入。Spring 支持多种自动装配策略,包括:
- no: 默认情况下,Spring 不会自动装配任何 Bean。
- byName: Spring 尝试根据属性名自动装配 Bean。
- byType: Spring 尝试根据类型自动装配 Bean。
- constructor: 类似于 byType,但适用于构造函数参数。
- autodetect: 如果存在带有一个参数的构造函数,则使用 constructor;否则使用 byType。
2 基础环境准备
1.新建module
- 打开现有的Maven项目。
- 添加新模块:
- 在IntelliJ IDEA中,右键点击项目的根目录 ->
New > Module...
-> 选择Maven Module
。 - 在Eclipse中,右键点击项目的
src/main/java
目录 ->New > Other...
-> 选择Maven
类别下的Module
。
- 在IntelliJ IDEA中,右键点击项目的根目录 ->
- 填写模块信息:
- 组织ID (
groupId
):与主项目相同。 - 艺术品ID (
artifactId
):模块的名称。 - 版本 (
version
):与主项目相同。 - 包装 (
packaging
):根据模块的功能选择war
、jar
或pom
。
- 组织ID (
- 完成创建:点击完成按钮,IDE将创建新的模块。
2.导入相关的依赖
在项目的pom.xml文件夹中导入一下依赖
<dependencies>
<!--导入spring-context依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.1.12</version></dependency>
<!--导入测试依赖-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!--导入日志框架--><dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.23.1</version>
</dependency><dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j2-impl</artifactId>
<version>2.23.1</version>
</dependency>
</dependencies>
注:导入依赖后需要刷新Maven,否则依赖不会导入
如果没有出现上面这个图标,你则需要进行如下步骤
idea===>最右边的栏===》Maven===>点击打开===》新弹出来的界面中===》点击刷新按钮==》就会出现Maven刷新图标====》点击刷新就能刷新了
3.新建SpringConfig配置文件
配置文件中的内容如下
<?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"></beans>
4.创建User类
下面是一个user类,name,age,有参构造,无参数构造,get,set方法
package org.xiji;public class User {private String name;private int age;public User(String name, int age) {this.name = name;this.age = age;}public User() {}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;}}
5.创建Teacher类
package org.xiji;public class Teacher {private User user;public Teacher(User user) {this.user = user;}public Teacher() {}/**** 点名*/ public void call() {System.out.println("老师点名"+user.getName()+"同学");}public User getUser() {return user;}public void setUser(User user) {this.user = user;}
}
3 在 XML 配置中启用自动装配
1.通过类型装配
在SpringConfig.xml中编写配置文件
<!--通过类型--> <bean id="userByType" class="org.xiji.User" autowire="byType"><property name="age" value="18"></property><property name="name" value="xiji"></property></bean> <bean id="teacher" class="org.xiji.Teacher" autowire="byType"></bean>
测试
注:可以看到,我们并没有配置和获取User相关的信息,但是调用teacher.call()点名方法时,却输出了我们在SpringConfig.xml文件中配置的user,但是我们也要注意,如果这个类有多个实例化对象时,会包错,错误原因是多个实例化对象,但不知道注入哪一个。
2.通过名称装配
在SpringConfig.xml中编写配置文件
<!--通过名字--> <bean id="teacher" class="org.xiji.Teacher" autowire="byName"></bean><bean id="user" class="org.xiji.User" autowire="byName"><property name="age" value="18"></property><property name="name" value="张三"></property> </bean>
测试结果
可以看到依旧可以成功
注:如果User的bean id与Teacher方法中属性名不一致时,使用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"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><!--通过名字--><bean id="teacher" class="org.xiji.Teacher" autowire="byName"></bean><bean id="userByName" class="org.xiji.User" autowire="byName"><property name="age" value="18"></property><property name="name" value="张三"></property></bean></beans>
错误收集
java.lang.NullPointerException: Cannot invoke "org.xiji.User.getName()" because "this.user" is null
at org.xiji.Teacher.call(Teacher.java:19)
at ByTypeTest.test(ByTypeTest.java:13)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)
at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
解决办法:
注入时,使用正确的名字,即可解决
4. 使用@Autowired注解中使用自动装配
1.配置componentScan包扫描
下面方法任选其中一种
1)在SpringConfig.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.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd "><!--配置包扫描--><context:component-scan base-package="org.xiji"></context:component-scan></beans>
注:把红色的替换为你自己的包路径,经过包扫描可以使用注解
2)配置类中配置
注:需要新建一个配置类,并且在类上加入@Configuration 和@ComponentScan("包名")
package org.xiji.config;import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;@Configuration
@ComponentScan("org.xiji")
public class MyConfig {}
2.@Autowired的使用
这里用javaweb中的视图控制层Controller和业务逻辑层Service层调用为例
1)基础准备
controller
package org.xiji.controller;import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.xiji.service.WebService;@Controller public class WebController {@AutowiredWebService webService;/*** 调用service*/public void call(){webService.call();} }
注:
@Autowired 自动装配注解
@Controller 这个是标注controller注解
@Resource 这个也是自动装配的注解
service
service接口
package org.xiji.service;public interface WebService {public void call(); }
service接口实现类
package org.xiji.service.impl;import org.springframework.stereotype.Service; import org.xiji.service.WebService;@Service public class WebServiceImpl implements WebService {public void call(){System.out.println("你好啊,我的Spring");} }
注:
@Service是service层的注解
2)测试
1.通过xml文件扫描配置文件测试
/*** 通过xml配置文件创建对象*/
@Test
public void test(){System.out.println("通过xml配置文件创建对象");ApplicationContext context = new ClassPathXmlApplicationContext("SpringConfig.xml");WebController webController = context.getBean("webController", WebController.class);webController.call();
}
2.通过config配置类测试
/*** 通过配置类创建对象*/@Test
public void test2(){System.out.println("通过配置类创建对象");ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);WebController webController = context.getBean("webController", WebController.class);webController.call();
}