(二)Spring-bean的作用域、xml和注解方式自动装配以及注解开发

(二)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"/>
<!-- the following is equivalent, though redundant (singleton scope is the default) -->
<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种装配方式

  1. 在xml中显示的配置
  2. 在java中显示配置
  3. 隐式的自动装配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>
<!-- ByName:会自动在容器上下文中查找,和自己对象set方法后面的值对应的bean-id-->
<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>
<!-- ByType:会自动在容器上下文中查找,和自己对象属性类型相同的bean-id-->
<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 使用条件

前提:

  • 和xml一样,所有依赖的类型都必须在xml即context中有了。

  • jdk1.5,spring2.5以后支持注解。

导入约束和注解支持<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;
// @Autowired
// @Qualifier(value = "dog2")
@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;
/*<!-- <bean id="user" class="com.happy.pojo.User"></bean>-->*/
@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;
/*<!-- <bean id="user" class="com.happy.pojo.User"></bean>-->*/
@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;
/*<!-- <bean id="user" class="com.happy.pojo.User"></bean>-->*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Component
//@Scope("singleton")
@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");
// 单例模式,每次get为同一个对象
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配置类

  • 使用java的方式配置spring,完全不用xml配置了,全权交给java来做

  • JavaConfig是Spring的一个子项目,在Spring 4之后,它成为另一个核心功能。

5.1 @Configuration介绍

1 使用和注册配置类

  • 在类上加上这个注解,代表该类是一个spring的配置类,等价于一个beans的application-context.xml文件。

  • 会被spring容器托管,注册到容器中,因为他本身也是一个component。

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
//@Component
//@ComponentScan("com.happy.pojo")
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中随处可见!

posted @   高兴518  阅读(103)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示

目录导航