(二)Spring-bean的作用域、xml和注解方式自动装配以及注解开发
一、 bean的作用域
1.1 定义
当您创建一个 bean 定义时,您创建了一个用于创建由该 bean 定义定义的类的实际实例的方法。bean 定义是一个配方的想法很重要,因为这意味着,与一个类一样,您可以从一个配方创建许多对象实例。
您不仅可以控制要插入到从特定 bean 定义创建的对象中的各种依赖项和配置值,还可以控制从特定 bean 定义创建的对象的范围。
这种方法功能强大且灵活,因为您可以通过配置选择您创建的对象的范围,而不必在 Java 类级别定义对象的范围。可以将 Bean 定义为部署在多个范围之一中。Spring 框架支持六个范围,其中四个仅在您使用 web-aware 时可用ApplicationContext
。您还可以创建 自定义范围。
1.2 六个作用域
Scope
Description
singleton
(Default)
Scopes a single bean definition to a single object instance for each Spring IoC container.
prototype
Scopes a single bean definition to any number of object instances.
request
Scopes a single bean definition to the lifecycle of a single HTTP request. That is, each HTTP request has its own instance of a bean created off the back of a single bean definition. Only valid in the context of a web-aware Spring ApplicationContext
.
session
Scopes a single bean definition to the lifecycle of an HTTP Session
. Only valid in the context of a web-aware Spring ApplicationContext
.
application
Scopes a single bean definition to the lifecycle of a ServletContext
. Only valid in the context of a web-aware Spring ApplicationContext
.
websocket
Scopes a single bean definition to the lifecycle of a WebSocket
. Only valid in the context of a web-aware Spring ApplicationContext
.
1 单例模式
spring默认机制
<bean id ="accountService" class ="com.something.DefaultAccountService" />
<bean id ="accountService" class ="com.something.DefaultAccountService" scope ="singleton" />
2 原型模式
每次从容器get的时候,都会产生一个新的对象!
<bean id ="accountService" class ="com.something.DefaultAccountService" scope ="prototype" />
3 其余的request,session,application
这些个只能在web 开发中使用的。
二、bean使用xml自动装配
2.1 定义
bean装配是spring满足bean依赖的一种方式!
spring会在上下文中自动寻找,并自动给bean装配属性!
2.2 spring中3种装配方式
在xml中显示的配置
在java中显示配置
隐式的自动装配bean【重要】
2.3 手动装配VS自动装配
2.3.1 手动装配
package com.happy.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor @AllArgsConstructor
public class People {
private String name;
private Dog dog;
private Cat cat;
}
package com.happy.pojo;
public class Cat {
public void shout () {
System.out.println("miao miao~" );
}
}
package com.happy.pojo;
public class Dog {
public void shout () {
System.out.println("wong wong ~" );
}
}
<?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 ="dog" class ="com.happy.pojo.Dog" > </bean >
<bean id ="cat" class ="com.happy.pojo.Cat" > </bean >
<bean id ="people" class ="com.happy.pojo.People" >
<property name ="name" value ="happy" > </property >
<property name ="dog" ref ="dog" > </property >
<property name ="cat" ref ="cat" > </property >
</bean >
</beans >
测试使用
package com.happy.service;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.happy.pojo.People;
public class PeoPleService {
@Test
public void test () {
ApplicationContext context = new ClassPathXmlApplicationContext ("application-context.xml" );
People people = context.getBean("people" , People.class);
System.out.println(people);
people.getDog().shout();
}
}
2.3.2 自动装配
1 ByName
注意:Byname是要保证,待装配对象的set方法和beanid一致,而并非待装配对象的属性名。
package com.happy.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
public class People {
private String name;
private Dog dog1;
private Cat cat;
public String getName () {
return name;
}
public void setName (String name) {
this .name = name;
}
public Dog getDog () {
return dog1;
}
public void setDog (Dog dog) {
this .dog1 = dog;
}
public Cat getCat () {
return cat;
}
public void setCat (Cat cat) {
this .cat = cat;
}
@Override
public String toString () {
return "People{" +
"name='" + name + '\'' +
", dog1=" + dog1 +
", cat=" + cat +
'}' ;
}
}
<?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 ="dog" class ="com.happy.pojo.Dog" > </bean >
<bean id ="cat" class ="com.happy.pojo.Cat" > </bean >
<bean id ="people" class ="com.happy.pojo.People" autowire ="byName" >
</bean >
</beans >
2 ByType
注意:
byType有自己的弊端,必须待装配对象的属性的类型保证在上下文里唯一
byType的依赖属性可以不用id都可以。
<?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 ="dog" class ="com.happy.pojo.Dog" > </bean >
<bean class ="com.happy.pojo.Cat" > </bean >
<bean id ="people" class ="com.happy.pojo.People" autowire ="byType" >
</bean >
</beans >
2.4 总结
byName的时候,需要保证所有bean的id唯一,并且这bean需要和自动注入的set方法后面的名字一致。
byType的时候,需要保证所有bean的class唯一,并且这bean需要和自动注入属性的类型一致。
三、bean使用注解自动装配
3.1 使用条件
前提:
导入约束和注解支持<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 >
实现如下:
<?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:aop ="http://www.springframework.org/schema/aop"
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/beans/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/beans/spring-aop.xsd" >
<bean id ="dog" class ="com.happy.pojo.Dog" > </bean >
<bean id ="cat" class ="com.happy.pojo.Cat" > </bean >
<bean id ="people" class ="com.happy.pojo.People" > </bean >
</beans >
3.2 @Autowired
直接在属性上使用即可,可以在属性和set方法上注入,相当于xml得到property
使用Autowired我们可以不用编写set方法了,前提是你这个自动装配的属性已经在IOC容器中存在,且符合按照ByType注入。
先按照type找相同类型的bean注入,如果容器中存在两个以上相同的,再按照set后面的name进行注入。即先ByType再ByName
如果ByType再ByName都存在两个以上(ByName没有找到相同的),则需要使用@Qualifier
3.3 @Qualifier
自动装配属性的时候,在容器中存在两个相同的type能匹配上,又不能匹配name,则需要使用这个注解。
即如果自动装配的环境比较复杂,自动装配无法通过一个注解@Autowired完成的时候,我们可以通过Autowired和Qualifier配合使用,就能指定一个唯一的bean对象注入
package com.happy.pojo;
import com.sun.istack.internal.NotNull;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
public class People {
private String name;
@Autowired
@Qualifier(value = "dog2")
private Dog dog;
@Autowired
private Cat cat;
public String getName () {
return name;
}
public void setName (String name) {
this .name = name;
}
@NotNull
public Dog getDog () {
return dog;
}
@Nullable
public void setDog (@NotNull Dog dog) {
this .dog = dog;
}
public Cat getCat () {
return cat;
}
public void setCat (Cat cat) {
this .cat = cat;
}
@Override
public String toString () {
return "People{" +
"name='" + name + '\'' +
", dog=" + dog +
", cat=" + cat +
'}' ;
}
}
3.4 @Resource
@Resource=@Autowired+@Qualifer
package com.happy.pojo;
import com.sun.istack.internal.NotNull;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import javax.annotation.Resource;
public class People {
private String name;
@Resource(name = "dog2")
private Dog dog;
@Autowired
private Cat cat;
public String getName () {
return name;
}
public void setName (String name) {
this .name = name;
}
@NotNull
public Dog getDog () {
return dog;
}
@Nullable
public void setDog (@NotNull Dog dog) {
this .dog = dog;
}
public Cat getCat () {
return cat;
}
public void setCat (Cat cat) {
this .cat = cat;
}
@Override
public String toString () {
return "People{" +
"name='" + name + '\'' +
", dog=" + dog +
", cat=" + cat +
'}' ;
}
}
3.5 Autowired vs @Resource
Autowired
Resource
相同点
自动装配
自动装配
不同点
先type后name
先name后type
四、使用注解开发
4.1 使用条件
在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"
xmlns:aop="http://www.springframework.org/schema/aop"
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
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd" >
<context:annotation-config></context:annotation-config>
<context:component-scan base-package ="com.happy.pojo" ></context:component-scan>
</beans>
导入约束和注解支持<context:annotation-config/>
注解驱动,加上这个就可以使用resource这些注解了
导入包扫描标签</context:component-scan>
扫描包
配置该标签后,如果除了这个包没有在其他地方注解了,就不需要再配置context:annotation-config
4.2 bean
4.2.1 @Component
将component放在类上,说明这个类被Spring 容器管理了,这就是bean。
相当于<bean id="user" class="com.happy.pojo.User"></bean>
package com.happy.pojo;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;
@Component
public class User {
public String name = "高兴" ;
@Override
public String toString () {
return "User{" +
"name='" + name + '\'' +
'}' ;
}
@Test
public void test () {
ApplicationContext context = new ClassPathXmlApplicationContext ("application-context.xml" );
User user = context.getBean("user" ,User.class);
System.out.println(user);
}
}
4.3 属性如何注入
4.3.1 @Value
@value注入可以不用set方法
相当于<property name="name" value="happybyxml"></property>
复杂类型,如map,list等还是建议用xml注入属性,而不用注解
package com.happy.pojo;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;
@Component
public class User {
@Value("happy518")
public String name ;
@Override
public String toString () {
return "User{" +
"name='" + name + '\'' +
'}' ;
}
@Test
public void test () {
ApplicationContext context = new ClassPathXmlApplicationContext ("application-context.xml" );
User user = context.getBean("user" ,User.class);
System.out.println(user);
}
}
4.3 衍生的注解
@Component有几个衍生注解,我们再web开发中,会按照mvc三层架构 分层。
这3个注解和@Component是等价的,人为定义@Component以后是注解非这3个注解的bean上
4.3.1 Dao层->@Repository
package com.happy.dao;
import org.springframework.stereotype.Repository;
@Repository
public class UserDao {
}
4.3.2 Service层->@Service
package com.happy.dao;
import org.springframework.stereotype.Repository;
@Repository
public class UserDao {
}
4.3.3 Controller层->@Controller
package com.happy.controller;
import org.springframework.stereotype.Controller;
@Controller
public class UserController {
}
4.4 自动装配置
见第三章节。
4.5 作用域
@Scope
package com.happy.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Scope;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Component
@Scope("prototype")
public class User {
@Value("happy518")
public String name ;
}
package com.happy;
import com.happy.pojo.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class UserTest {
@Test
public void test () {
ApplicationContext context = new ClassPathXmlApplicationContext ("application-context.xml" );
User user1 = context.getBean("user" , User.class);
User user2 = context.getBean("user" , User.class);
System.out.println(user1 == user2);
}
}
4.6 小结
XML vs 注解
Xml
注解
不同
xml更加万能,适用于任何场合!
注解:不是自己类使用不了
集中管理,维护简单
维护相对复杂
解耦
耦合较强
最佳实践:
xml用来管理bean
注解负责完成属性注入
我们再使用的过程中,只需要注意一个问题,必须要让注解生效,必须开启注解的支持
五、使用Java配置类
5.1 @Configuration介绍
1 使用和注册配置类
2 使用配置类注册bean
注册一个bean,就相当于我们之前写的一个bean标签
配置类中的方法名字,就相当于bean标签中的id属性。
这个方法的返回类型,就相当于bean标签中的class属性。
方法的返回对象就是要注入bean的对象
3 获取容器
完全使用了配置类方式去做的方式,我们需要通过ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class)来获取容器了。
5.2 配置类使用步骤
1 实体类
package com.happy.pojo;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
@Data
public class User {
@Value("gaoxing")
private String name;
}
2 配置类:
package com.happy.config;
import com.happy.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
@Configuration
public class MyConfig {
@Bean
public User getUser () {
return new User ();
}
}
3 测试类
package com.happy;
import com.happy.config.MyConfig;
import com.happy.pojo.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class UserTest {
@Test
public void test () {
ApplicationContext context = new AnnotationConfigApplicationContext (MyConfig.class);
User user = (User) context.getBean("getUser" );
System.out.println(user);
}
}
这种纯java的配置方式,在SpringBoot中随处可见!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】