您现在的位置是:首页 >技术教程 >Spring BeanFactory 和 ApplicationContext网站首页技术教程

Spring BeanFactory 和 ApplicationContext

哇塞大嘴好帅(DaZuiZui) 2024-07-01 11:59:39
简介Spring BeanFactory 和 ApplicationContext

Spring BeanFactory 和 ApplicationContext

BeanFactory

​ Beanfactory是Spring IOC的基本接口,他定义了容器最基本的功能,提供了对Bean的注册、获取和管理能力。

​ BeanFactory使用延迟初始化策略,也就是说,当你从容器中获取一个Bean时,才会真正的创建和初始化Bean。

​ BeanFactory对于资源的消耗比较小,因为它只在需要的时候才会创建Bean对象,适合资源受限的环境。

​ DefaultListableBeanfactory是BeanFactory接口的一个常见实现类,提供了对Bean的定义、解析和注册的功能。

BeanFactory对AOP的支持

// 创建BeanFactory实例
BeanFactory beanFactory = new DefaultListableBeanFactory();

// 创建切面类
@Aspect
public class MyAspect {
    @Before("execution(* com.example.MyService.doSomething())")
    public void beforeAdvice() {
        // 执行前置通知逻辑
        System.out.println("Before advice executed");
    }
}

// 创建目标类
public class MyService {
    public void doSomething() {
        // 执行业务逻辑
        System.out.println("Doing something");
    }
}

// 注册切面和目标类
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
registry.registerBeanDefinition("myAspect", new RootBeanDefinition(MyAspect.class));
registry.registerBeanDefinition("myService", new RootBeanDefinition(MyService.class));

// 创建AOP代理对象
AopProxyFactory proxyFactory = new DefaultAopProxyFactory();
Advisor[] advisors = new Advisor[]{new DefaultPointcutAdvisor(new AspectJExpressionPointcut(), new MyAspect())};
Object target = beanFactory.getBean("myService");
Object proxy = proxyFactory.createAopProxy(target, advisors).getProxy();

// 将AOP代理对象注册到BeanFactory中
beanFactory.registerSingleton("myServiceProxy", proxy);

// 获取AOP代理对象
MyService myService = beanFactory.getBean("myServiceProxy", MyService.class);

// 调用目标方法
myService.doSomething();

BeanFactory需要做一些手动配置,如AOP代理对象进行绑定。 很麻烦

DefaultListableBeanFactory

​ 上文我们所说到DefualtListableBeanFactory提供了Bean的定义、解析和注册的功能。

Bean的定义

Bean的定义描述了如何创建和配置一个特定的Bean。它通常包括Bean的类名(Bean的class)、依赖关系、属性值和初始化方法等信息。

<bean id="myBean" class="com.example.MyBeanClass">
    <!-- Bean的属性和配置 -->
</bean>

在这个例子中,“com.example.MyBeanClass” 是要实例化的Bean的类名。

定义Bean的类

就是创建一个Java类,表示我们要创建的Bean,这个类可以包括属性、方法和构造函数以满足特定的业务需求。

public class Builder {
    private Long id;
    private String name;
    private Integer maxFloor; //最大楼层
    private String sex;      //所属性别

    @Override
    public String toString() {
        return "Builder{" +
                "id=" + id +
                ", name='" + name + ''' +
                ", maxFloor=" + maxFloor +
                ", sex='" + sex + ''' +
                '}';
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getMaxFloor() {
        return maxFloor;
    }

    public void setMaxFloor(Integer maxFloor) {
        this.maxFloor = maxFloor;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public Builder() {
    }

    public Builder(Long id, String name, Integer maxFloor, String sex) {
        this.id = id;
        this.name = name;
        this.maxFloor = maxFloor;
        this.sex = sex;
    }
}

注册声明Bean

​ 声明bean主要做的就是指定Bean的类名、属性值和依赖关系。

xml配置文件声明bean
<!-- 声明一个名为 "userService" 的Bean,类为 "com.example.UserService" -->
<bean id="userService" class="com.example.UserService">
   <!-- 设置属性值 -->
   <property name="name" value="John Doe" />
   <property name="age" value="30" />
   
   <!-- 设置依赖关系 -->
   <property name="userDao" ref="userDao" />
</bean>

<!-- 声明一个名为 "userDao" 的Bean,类为 "com.example.UserDao" -->
<bean id="userDao" class="com.example.UserDao" />

注解声明Bean
@Component
public class UserService {
    @Value("John Doe")
    private String name;
    
    @Value("30")
    private int age;
    
    @Autowired
    private UserDao userDao;
    
    // Bean的其他方法和逻辑...
}
配置Bean的作用域
注解定义作用域
@Component
@Scope("prototype")
public class MyPrototypeBean {
    // Bean的实现代码...
}

xml定义的作用域
<bean id="mySingletonBean" class="com.example.MySingletonBean" scope="singleton" />

<bean id="myPrototypeBean" class="com.example.MyPrototypeBean" scope="prototype" />
配置Bean属性
注解
@Component
public class MyBean {
    @Value("John Doe")
    private String name;
    
    @Value("30")
    private int age;
    
    // Getter and Setter methods...
}

xml
<bean id="myBean" class="com.example.MyBean">
    <property name="name" value="John Doe" />
    <property name="age" value="30" />
</bean>

解析

​ Bean的解析是指Bean 的定义转移为容器内部结构的过程,方便容器能够理解管理这些Bean,在解析过程中,容器会读取和解析XML配置文章、扫描并解析Java注解或处理Java代码,以获取Bean的定义信息。解析过程中容器会创建对应的数据结构(如BeanDefinition对象)来表示每个Bean的定义,并将其粗处容器的内部数据结构中。

​ 定义初始化方法也就是在解析阶段做的,定义初始化方法就是销毁前,初始化方法。

​ 当Spring启动的时候,他就会解析配置文件或者注解中,创建和注册的Bean,这意味着spring会是实列化该Bean,并根据配置文件中的设置来注入依赖关系和属性值。

注册

​ Bean的注册是将解析到的Bean定义注册到容器中的过程,这样容器就能够管理这些Bean,并在需要的时候进行创建和管理。

​ 在注册过程中,容器将解析到的Bean定义与其一的标识符(通常Bean的name和id)相关联,并将其存储在容器的Bean注册表中。

​ 注册的方法取决于使用的配置方式,在XML配置文件中你可以使用元素的id或者name属性来指定Bean的标识符。在使用Java注解或Java代码时,通常使用注解元数据或方法名作为Bean的标识符。如果id和name同时出现那么id优先级最高,因为name只是一个别名。

获取Bean实列

​ 一旦Bean被注入到容器,就可以通过容器获取到该Bean。

BeanDefinition

​ 上面我们在解析的时候说到,在解析的时候会创建Definition对象,它包含了描述bean的元数据信息,例如Bean的类名、作用域、构造函数参数、属性值、初始化方法、销毁方法等。他主要做的就是用于描述和管理Bean的配置和创建过程。

​ 每个注册到Spring容器的bean都对应一个的BeanDefinition对象,当Spring容器扫描注解或者去读和解析xml配置文件的时候他就会将这些配置信息创建到对应的BeanDefinition对象。

​ 通过BeanDefinition,Spring容器可以了解Bean的特征和配置细节,以便在需要的时候创建的、管理和使用Bean。BeanDefinition的信息可以让我们的Spring容器能狗实现依赖注入、AOP(需要BeanDefinition和Aop配置文件结合,spring会根据AOP配置判断哪些Bean需要创建AOP代理对象,并将AOP的横切逻辑织入到这些Bean的方法调用中。)、生命周期管理等功能。

​ BeanDefinition的实现类有GenericBeanDefinition和RootBeanDefinition

BeanDifnition与AOP的结合

​ BeanDefinition与AOP的结合是通过AOp相关的配置元素或者注解实现的。BeanDefinition中PropertyValues属性可以用来设置Bean的属性值,包括AOP相关的配置信息。可以使用propertyValues来设置切换(Aspect)、切入点(Poinicut)和通知(Advice)对象等

GenericBeanDefinition

默认情况下BeanDefinition的实现类都是GenericBeanDefinition

属性设置

​ 它可以设置Bean的各种属性、包括类型、作用域、构造函数参数、属性值等。

依赖关系管理

​ GenericBeanDefinition可以声明Bean之间的依赖关系,以实现依赖注入。

初始化和销毁方法

​ 它可以指定Bean在创建后需要执行的初始化方法和在销毁前执行的方法、

RootBeanDifinition

​ RootBeanDIfinition是BeanDifinition的另外一个实现类,他可以贡献作用域(Scope)和初始化方法(init-method)等配置属性。

@Configuration
public class AppConfig {
    @Bean
    public RootBeanDefinition myBeanDefinition() {
        RootBeanDefinition beanDefinition = new RootBeanDefinition(MyBean.class);
        // 设置其他属性或依赖关系
        beanDefinition.setScope("singleton");
        beanDefinition.setInitMethodName("init");
        beanDefinition.setDestroyMethodName("destroy");
        return beanDefinition;
    }

    @Bean
    public MyBean myBean() {
        return new MyBean();
    }
}

ApplicationContext

​ ApplicationContext是BeanFactory的子接口主要提供了更多的功能和扩展性和便捷性。

​ ApplicationContext负责管理和维护Bean的声明周期,主要提供了以下的功能

**1.Bean的创建和管理:**ApplicationContext负责实例化、配置和管理Bean,他会根据xml文件或者注解解析Bean的定义根据需求创建Bean。

2.依赖注入:ApplicationContext可以自动解决Bean之间的依赖关系,它会根据Bean的定义信息,自动将依赖的bean注入到目标Bean中,实现解耦和组件之间的协作

**3.AOP支持:**可以配置和管理切面和切入点和通知。

4.事件的发布和监听:就是APplicationContext发布一条信息让已注册的监听器让他们执行相应的处理操作

​ 创建一个自定义事件类:这个自定义类要继承ApplicationEvent

public class MyCustomEvent extends ApplicationEvent {
    // 自定义事件类的构造方法
    public MyCustomEvent(Object source) {
        super(source);
        // 可以在这里设置事件相关的属性
    }
    // 自定义事件类的其他方法和属性
}

然后通过ApplicationContext.publishEvent();方法进行发布事件

事务的监听实现ApplicationListener进行监听

@Component
public class MyCustomEventListener implements ApplicationListener<MyCustomEvent> {
    @Override
    public void onApplicationEvent(MyCustomEvent event) {
        // 在这里编写事件处理逻辑
        // 可以访问事件相关的数据和信息
    }
}

**5.国际化支持:**ApplicationContext提供国际化的支持,可以根据不同的语言和地区,加载相应的资源文件

**6.生命周期管理:**ApplicationContext管理Bean的声明周期,包括Bean的初始化、销毁、和回收。他会在合适的时候调用Bean的生命周期回调方法,确保Bean在创建和销毁的时候执行必要的操作。

ApplicationContext对Aop的支持

​ 虽然BeanFactory也支持AOP,但是在实际使用中ApplicationContext更加便捷,ApplicationContext内部继承了AOP相关的功能,包括切面、切点、通知等,可以直接使用注解或或者配置来实现Aop相比之下BeanFacotry需要手动配置和管理AOP的相关组件,比较麻烦。

​ ApplicationContext和BeanFactory比起来它更加的方便,不需要手动AOP代理对象的绑定,它提供了自动扫描和解析AOP的能力**@EnableAspectAutoProxy**

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.annotation.aspectj.EnableSpringConfigured;
import org.springframework.stereotype.Component;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Configuration
@EnableAspectJAutoProxy
@EnableSpringConfigured
public class AppConfig {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
        
        MyBean myBean = context.getBean(MyBean.class);
        myBean.doSomething();
        
        context.close();
    }
}

@Component
class MyBean {
    public void doSomething() {
        System.out.println("Doing something...");
    }
}

@Aspect
@Component
class MyAspect {
    @Before("execution(* com.example.MyBean.doSomething())")
    public void beforeAdvice() {
        System.out.println("Before advice executed");
    }
}

@EnableAspectAutoProxy

​ @EnableAspectAutoProxy通过在配置类上添加该注解,我们可以启动Spring框架对AOP注解和自动扫描和解析。就可以通过注解自动进行AOP对象的绑定,不需要我们手动配置

​ @EnableAspectAutoProxy注解告诉Spring容器要使用AspectJ自动代理功能来实现AOP,他会扫描应用上下中的Bean,并检查他们是否有被@Aspect注解标记切面类,如果发现了切面类,它就会为这些切面创建代理对象,并将他们应用到合适的目标bean上,如果遇见AOP相关的注解@before、@After那么Spring就会扫描这些注解,并且为他们做相应的切面逻辑。

​ @EnableAspectAutoProxy提供了自动扫描和解析AOP注解的能力,使得我们更加方便的配置和使用AOP功能。

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。