4-spring篇

news2025/1/4 18:49:55

ApplicationContext refresh的流程

12个步骤

  1. prepareRefresh
    这一步创建和准备了Environment对象,并赋值给了ApplicationContext的成员变量
    要理解Environment对象的作用

  2. obtainFreshBeanFactory
    ApplicationContext 里面有一个成员变量,Beanfactory
    bean的来源有 xml配置文件,配置类,扫描

  3. prepareBeanFactory

  4. postProcessBeanFactory
    是一个空实现,留给子类实现的

  5. invokeBeanFactoryPostProcessors
    bean工厂后处理器

  6. registerBeanPostProcessors
    注册bean后处理器 对bean的创建过程中,各种功能的增强

  7. initMessageSource
    MessageSource实现国际化的

  8. initApplicationEventMulticaster
    应用事件广播器

  9. onRefresh
    空实现,留给子类实现

  10. registerListeners
    事件监听器

  11. finishBeanFactoryInitialization

  12. finishRefresh

spirng bean 生命周期

  1. 阶段一:处理名称,检查缓存
    • 1.1 把别名解析成实际名称,再进行后续处理
    • 1.2若要factoryBean本身,需要使用&名称获取
    • 1.3singletonobjects是一级缓存,放单例成品对象
    • 1.4singletonFactories是三级缓存,放单例工厂
    • 1.5earlySingletonObjects是二级缓存,放单例工厂的成品,可称为提前单例对象

2.阶段二:检查父工厂
- 1.父子容器的bean名称可以重复
- 2.优先找子容器的bean,找到了直接返回,找不到继续到父容器找

3.阶段三:检查DependsOn

4.阶段四:按Scope 创建bean
* 1.创建singleton
* 2.创建prototype
* 3.创建其他scope

  1. 阶段五:创建bean

    • 1.创建bean实例 @Autowired,唯一带参构造,默认构造
    • 2.依赖注入 @Autowired @value@Resource,ByName ByType 精确指定
    • 3.初始化- Aware接口处理,@PostConstruct,InitializingBean,initMethod
    • 4.登记可注销bean
  2. 类型转换

  3. 销毁bean

spring 事务失效的几种场景及原因

1.抛出检查异常导致事务不能正确回滚
spring默认情况下,只对,runtimeException,和Error这两个异常及其子类会回滚。如果是检查异常,是不会回滚的
解决方案:
@Transactional(rollbackFor = Exception.class)

2.业务方法内自己try-cach 异常导致事务不能正确回滚
原因:事务通知只有捉到了目标抛出的异常,才能进行后续的回滚处理,如果目标自己处理掉异常,事务通知无法知悉
解决1:异常原样抛出
解决2:手动设置TransactionStatus.setRollbackOnly()

3.aop切面顺序导致事务不能正确回滚
原因:事务切面优先级最低,但如果自定义的切面优先级和他一样,则还是自定义切面在内层,这时若自定义切面没有正确抛出异常,那外层的事务切面没有办法感知异常。
解法:同情况2

4.@Transactional 一定要放在public的方法上,否则无效
原因:spring为方法创建代理、添加事务通知、前提条件都是该方法是public的

5.父子容器导致的事务失效
原因:子容器的扫描范围过大,把未加事务配置的service扫描进来
解法1:各扫描各的,不要图简便
解法2:不要用父子容器,所有bean放在同一个容器

6.调用本类方法导致传播行为失效
原因:本类方法调用不经过代理,因此无法增强
解法1:依赖注入自己(代理)来调用
解法2:通过AopContext拿到代理对象,来调用
解法3:通过CTW,LTW实现功能增强

  1. @Transactional没有保证原子行为
    原因:事务的原子性仅涵盖insert,update,delete,select…for update语句,select方法并不阻塞
    8.@Transactional方法导致的synchronized失效
    原因:synchronized保证的是目标方法的原子性,环绕目标方法的还有commit等操作,他们并未处于sync块内

解法1:synchronized 范围阔大至代理方法调用
解法2:使用select…for update替换select

SpringMVC 执行流程

初始化阶段:
1.在Web容器第一次用到DispatcherServlet的时候,会创建其对象并执行init方法
2.init方法会创建Spring Web容器,并调用容器refresh方法

3.refresh过程中会创建并初始化SpringMVC中的重要组件,例如MultipartResolver,HandlerMapping,HandlerAdapter,HandleExceptionResolver,ViewResolver等
4.容器初始化后,会将上一步初始化好的重要组件,赋值给DispatcherServlet的成员变量,留待后用

匹配阶段:
1.用户发送的请求统一到达的前端控制器DispatcherServlet
2.DispatcherServlet遍历所有HandlerMapping,找到与路径匹配的处理器对象

  • 1.HandlerMapping有多个,每个HandlerMapping会返回不同的处理器对象,谁先匹配,返回谁的处理器。其中能识别@RequestMapping的优先级最高
  • 2.对应@RequestMapping的处理器是HandlerMethod,它包含了控制器对象和控制器方法信息
  • 3.其中路径与处理器的映射关系在HandlerMapping初始化时就会建立好
    3.将HandlerMethod连同匹配到拦截器,生成调佣链对象HandlerExecutionChain返回
    4.遍历HandlerAdpter处理器适配器,找到能处理HandlerMethod的适配器对象,开始调用

执行阶段:
1.执行拦截器preHandle
2.由HandlerAdapter(适配器)调用HandlerMethod(处理器)

  • 1.调用前处理不同类型的参数
  • 2.调用后处理不同类型的返回值
    3.第二步没有异常
  • 1.返回ModelAndView
  • 2.执行拦截器postHandle方法
  • 3.解析视图,得到View对象,进行视图渲染
    4.第2步有异常,进入HandlerExceptionResolver异常处理流程
    5.最后都会执行拦截器的afterCompletion方法
    6.如果控制器方法标注了@ResponseBody注解,则在第二步,就会生成json结果,并标记ModelAndView已处理,这样就不会执行第3步的试图渲染

spring注解大全

1.事务
@EnableTransactionManagement 启用声明式的事务
@Transactional
2.核心
@Order 多个bean控制执行顺序
3.切面
@EnableAspectAutoProxy 启用Aop自动代理
以下这些不是spring的注解,是第三方spring-aspects的注解
@Aspect //标记该类为切面类
@Before
@After
4.组件扫描和配置类的
@Component
@Controller
@Service
@Repository
@ComponentScan
@Conditional 组件扫描时,做条件判断 bean加载时,做条件判断
@Configuration
@Bean
@Import
@Lazy 标注在类上,表示类是延迟实例化和初始化的
@PropertySource 加载外部properties文件
5.缓存
@EnableCaching
@CacheConfig
@CacheEvict
@CachePut
@Cacheable
@Caching
6.依赖注入
@Autowired
@Qualifier 依赖注入时,同一类型有多个bean,可以用名字进行区分
@Value
7.mapping
@Mapping
@RequestMapping 建立请求路径和控制器方法的映射关系
@GetMapping
@PostMapping
@PutMapping
@DeleteMapping
@PatchMapping
8.rest
@RequestBody 请求体里面的json数据,转换成java数据
@ResponseBody,将java数据,转换成json数据放到响应体
@ResponseStatus控制响应的状态
@RestController
是一个组合注解 组合了: @Controller 和 @ResponseBody
9.统一处理
@ControllerAdvice
@ExceptionHandler
@RestControllerAdvice
10.参数
@RequestHeader 请求头的信息
@CookieValue
@PathVariable 获取路径参数
@RequestParam 获取请求参数 ?后的,或者表单的
11.转换和格式化
@DateTimerFormat
@NumberFormat
@InitBinder
12.validation bean的校验
@Validated
13 scope
@ApplicationScope
@RequestScope
@SessionScope
@ModelAttribute
@RequestAttribute
@SessionAttribute
@SessionAttributes
14.ajax
@CrossOrigin 解决ajax的跨域问题
spring-boot注解
1.@EnableConfigurationProperties 启用
2.@ConfigurationProperties bean 值的初始化
3.@Configuration!!!!!!!!!!!!!!!!!!!!

注意:

    1. 配置类其实就相当于一个工厂。
    1. @bean注解的方法,就是工厂方法 @Bean,不支持方法重载,如果有多个重载方法,仅有一个能入选为工厂方法。参数越多,权重越高
	  	@Bean
        public Bean1 bean1(){
            System.out.println("new bean2.....");
            return new Bean1();
        }
        @Bean
        public Bean1 bean1(@Value("${java.class.version}") String a){
            System.out.println("a:"+a);
            return new Bean1();
        } 
        @Bean //这个参数有2个权重高
        public Bean1 bean1(@Value("${java.class.version}") String a,@Value("${JAVA_HOME}") String b){
            System.out.println("bena1 a:"+a+" b:"+b);
            return new Bean1();
        }
    1. 注意点3:@Configuration 默认会为标注的类生成代理,其目的是保证@Bean 方法互相调用时,仍然能保证其单例特性
  • 4.注意点4:@Configuration中如果含有BeanFactory 后处理器,则实例方法会导致MyConfig提前创建,造成其依赖注入失败。

//	问题复现
public class TestConfiguration {
    public static void main(String[] args) {
        GenericApplicationContext context = new GenericApplicationContext();
        AnnotationConfigUtils.registerAnnotationConfigProcessors(context.getDefaultListableBeanFactory());
        context.registerBean("myConfig",Myconfig.class);
        context.refresh();
        System.out.println(context.getBean(Myconfig.class));
        System.out.println();

    }
    @Configuration()
    static class Myconfig{


        @Bean
        public Bean1 bean1(){
            System.out.println("bean1().....");
            return new Bean1();
        }

        @Bean
        public Bean2 bean2(){
            System.out.println("bean2().....");
            return new Bean2();
        }

        @Value("${java.class.version}")
        private String version;

        @Bean	//	这个实现了BeanFactory后处理器
        public  MapperScannerConfigurer configurer(){
            MapperScannerConfigurer scanner = new MapperScannerConfigurer();
            scanner.setBasePackage("aaa");
            return scanner;
        }

        @Bean
        public Bean3 bean3(){
            System.out.println("Bean3():"+version);		//	这个version无法获取了,因为提前有后处理器在这个Configuration类里面,所以这个Myconfig提前创建了,所以他的功能没有增强。@Value 这些增强没有了。
            return new Bean3();
        }

        class Bean3{}

        class Bean1{}

        class Bean2{}
    }
}

  • 解决办法:
      1. bean工厂后处理器在配置类中定义,就用 static 修饰
      1. 如果想在@Bean修饰的方法依赖注入,用局部变量就可以,用参数注入,尽量不要用成员变量来注入
    @Bean
        public Bean3 bean3(@Value("${java.class.version}") String version){
            System.out.println("Bean3():"+version);		//	这个version无法获取了,因为提前有后处理器在这个Configuration类里面,所以这个Myconfig提前创建了,所以他的功能没有增强。@Value 这些增强没有了。
            return new Bean3();
        }
    

15.@Import 放在 @Configuration配置类上
import5种用法

public class TestImport {
    public static void main(String[] args) {
    	//	普通容器
        GenericApplicationContext context = new GenericApplicationContext();

		//后处理器
        AnnotationConfigUtils.registerAnnotationConfigProcessors(context.getDefaultListableBeanFactory());
        //注册bean
        context.registerBean(Myconfig.class);
        //refresh
        context.refresh();

        for (String name : context.getBeanDefinitionNames()) {
            System.out.println(name);
        }

    }
    @Configuration
//    @Import(bean1.class)          //  1.引入单独bean
//    @Import(OtherConfig.class)    //  2.引入一个配置类
//    @Import(MySelector.class)      //   3.通过MySelector实现了引入多个类 ,MySelector本身不会注册成bean
//    @Import(MyRegister.class)      //   4.通过MyRegister注册器引入多个类,MyRegister本身不会注册成bean
    @Import(MySelector2.class)      //   5.通过MySelector2注册器实现了DeferredImportSelector引入多个类,MySelector2本身不会注册成bean
    static class Myconfig{

    }

    static class MySelector2 implements DeferredImportSelector{

        @Override
        public String[] selectImports(AnnotationMetadata importingClassMetadata) {
            return new String[]{Bean3.class.getName(),Bean4.class.getName()};
        }
    }
    static class MyRegister implements ImportBeanDefinitionRegistrar {
        @Override
        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
            registry.registerBeanDefinition("bean5", BeanDefinitionBuilder.genericBeanDefinition(Bean5.class).getBeanDefinition());
        }


    }
    static class MySelector implements ImportSelector{
        @Override
        public String[] selectImports(AnnotationMetadata importingClassMetadata) {
            return new String[]{Bean3.class.getName(),Bean4.class.getName()};
        }
    }

    @Configuration
    static class OtherConfig{
        @Bean
        public Bean2 bean2(){
            return new Bean2();
        }
    }
    static class bean1{}
    static class Bean2{}
    static class Bean3{}
    static class Bean4{}
    static class Bean5{}
}

16.@Import-DeferredImportSelector


public class TestDeferredImport {
    public static void main(String[] args) {
        GenericApplicationContext context = new GenericApplicationContext();
        DefaultListableBeanFactory beanFactory = context.getDefaultListableBeanFactory();
        beanFactory.setAllowBeanDefinitionOverriding(false);    //  不允许同名定义覆盖
        AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
        context.registerBean(Myconfig.class);
        context.refresh();

        System.out.println(context.getBean(MyBean.class));

    }

    //  1.同一个配置类中,@Import 先解析 @Bean 后解析
    //  2.同名定义,默认后面解析的会覆盖前面解析的
    //  3.不允许覆盖的情况下,如何能让Myconfig(主配置类)的配置优先?(虽然覆盖方式能解决)
    //  4.@Import 导入的类MyDeferredImportSelector 实现了DeferredImportSelector 最后工作,可以简单认为先解析@Bean,再解析@Import
    @Configuration
    @Import(MyDeferredImportSelector.class)
    static class Myconfig{  //  主配置 -程序员自己配置的
        @Bean
        public MyBean myBean(){
            return new Bean1();
        }
    }
    static class MyDeferredImportSelector implements DeferredImportSelector{
        @Override
        public String[] selectImports(AnnotationMetadata importingClassMetadata) {
            return new String[]{OtherConfig.class.getName()};
        }
    }

    @Configuration
    static class OtherConfig{   //  从属配置 - 自动配置
        @Bean
        @ConditionalOnMissingBean
        public MyBean myBean(){
            return new Bean2();
        }
    }

    interface MyBean{}

    static class Bean1 implements MyBean {}
    static class Bean2 implements MyBean {}
}

Springboot 自动配置

@SpringbootApplication 是一个组合注解这个注解包含下面这些

  • @SpringBootConfiguration 标记了这个类其实就是个配置类,没什么特别的
  • @ComponentScan 用来在组件扫描时进行排除,也会排除自动配置类
  • @EnableAutoConfiguration是一个组合注解
    • @AutoConfigurationPackage -用来记住扫描的起始包
    • @Import(AutoConfigurationImportSelector.class)可以分离主从配置。用来加载META-INF/spring.factories中的自动配置类

Spring中有哪些设计模式

1.Spring中的Singleton Bean 是否是单例模式?

  • spring中的singleton bean 并非实现了单例模式,singleton bean 只能保证每个容器内,想通的id的bean单例
  • spirng中也有单例模式

2.Spring中的Builder 构建器模式
他的主要亮点有三处:
1.较为灵活的构建产品对象
2.在不执行最后的build方法前,产品对象都不可用
3.构建过程采用链式调佣,看起来比较爽
spring中体现Builder模式的地方:

  • org.springframework.beans.factory.support.BeanDefinitionBuilder
  • org.springframework.web.util.UriComponentsBuilder
  • org.springframework.http.ResponseEntity.HeadersBuilder
  • org.springframework.http.ResponseEntity.BodyBuilder

3.Spirng中的Factory Method 工厂方法模式

4.Spring 中的 Adapter 适配器模式
把一套接口转换成调用者所期望的接口

5.Spring 中的 Composite 组合器模式

6.spring 中的 Decorator 装饰器模式
对目标对象做功能增强,避免子类继承进行功能可扩展

7.spring中的 Proxy 代理模式
对目标对象的控制和访问

8.Spring 中的 Chain of Responsibility 责任链模式
拦截器

9.Spirng 中的 Observer 观察者模式

ApplicationListener 监听器
ApplicationEventMulticaster 发送器
ApplicationEvent 事件对象

10.Spring 中的Strategy 策略模式

11.Spring 中 的 Template Method 模板方法

  • 大部分以Template 命名的类, 如jdbcTemplate TransactionTemplate
  • 很多以 Abstract命名的类,如AbstractApplicationContext

创建代理要点:

  • 要完全理解循环依赖,需要理解代理对象的创建时机
  • 掌握proxyFactory创建代理的过程,理解Advisor,Advice,Ponitcut 与 Aspect
  • 掌握AnnotationAwareAspectJAutoProxyCreator筛选Advisor合格者,创建代理的过程
    proxyFactory的基本使用
    总结:
  • Advisor 是最基本的切面,Aspect 切面对应一个或多个Advisor切面
  • 最基本的Advice 是MethodInterceptor,其他的Advice最终都将适配为MethodInterceptor
  • 创建代理的方式:
    • 实现了用户自定义接口,采用jdk动态代理
    • 没有实现用户自定义接口,采用cglib代理
    • 设置了setProxyTargetClass(true),同意采用cglib代理
  • 切面、切点、通知等不会被代理
  • AnnotationAwareAspectJAutoProxyCreator 调用时机:创建阶段、依赖注入阶段、初始化阶段
//	编程方式
public class APP64_2 {
    public static void main(String[] args) {
        //  aspect = (通知)advice + pointcut(切点),一个切面类可能有一个多个通知方法
        //  advisor = 更细粒度的切面,包含一个通知和切点

        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.setTarget(new Target1());  //  设置目标对象
        
        //  添加通知:MethodInterceptor 是环绕通知
//        proxyFactory.addAdvice((MethodInterceptor) invocation -> {
//            try {
//                System.out.println("befor...");
//                return invocation.proceed();    //  调用目标
//            } finally {
//                System.out.println("atfer....");
//            }
//        });

        //  设置切点
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression("execution(* foo())");



        proxyFactory.addAdvisor(new DefaultPointcutAdvisor(pointcut, (MethodInterceptor) invocation -> {
            try {
                System.out.println("before1...");
                return invocation.proceed();    //  调用目标
            } finally {
                System.out.println("after1...");
            }

        }));

        proxyFactory.addAdvisor(new DefaultPointcutAdvisor(pointcut, (MethodInterceptor) invocation -> {
            try {
                System.out.println("before2...");
                return invocation.proceed();    //  调用目标
            } finally {
                System.out.println("after2...");
            }

        }));


        proxyFactory.addInterface(I1.class);
//        proxyFactory.setProxyTargetClass(true);
        I1 proxy = (I1) proxyFactory.getProxy();  //  创建代理对象
        System.out.println(proxy.getClass());
        proxy.foo();
        proxy.bar();


    }

    interface I1{
        void foo();
        void bar();
    }

    static class Target1 implements I1{

        @Override
        public void foo() {
            System.out.println("target1 foo");
        }

        @Override
        public void bar() {
            System.out.println("target1 bar");

        }
    }

}

//	使用注解的方式
package org.springframework.aop.framework.autoproxy;

public class APP64_1 {
    public static void main(String[] args) {
        GenericApplicationContext context = new GenericApplicationContext();

        context.registerBean("aspect1",Aspect1.class);
        context.registerBean("aspect2",Aspect2.class);
        context.registerBean("aspect3",Aspect3.class);
        context.registerBean(AnnotationAwareAspectJAutoProxyCreator.class); //  自动代理后处理器

        context.refresh();
        AnnotationAwareAspectJAutoProxyCreator creator = context.getBean(AnnotationAwareAspectJAutoProxyCreator.class);
		//	这里是演示一下 自动代理后处理器 是怎么创建代理对象的
//		wrapIfNecessary 是protected 为了实验可以成功,把这个当前这个类放在了同包下测试
        Object o = creator.wrapIfNecessary(new Target1(), "target1", "target1");
        System.out.println(o.getClass());	//	是代理类
        Object b = creator.wrapIfNecessary(new Aspect1(), "aspect1", "aspect1");
        System.out.println(b.getClass());	//	Aspect1是aop的基础设施,所有就不用代理对象

    }

    @Aspect
    static class Aspect1{
        @Around("execution(* com.libin..autoproxy..foo())")   //  对应成一个Advisor切面
        public Object around(ProceedingJoinPoint pjp) throws Throwable {
            try {
                System.out.println("aspect1 around before");
                return pjp.proceed();
            } finally {
                System.out.println("after....");
            }
        }
    }

    @Aspect
    static class Aspect2{   //  对应成两个Advisor切面
        @Before("execution(* foo())")
        public void before()  {
            System.out.println("aspect2 before");
        }

        @After("execution(* foo())")
        public void after()  {
            System.out.println("aspect2 after");

        }
    }

    @Aspect
    static class Aspect3{
        @Before("execution(* bar())")   //  对应成一个Advisor切面
        public void around()  {
            System.out.println("aspect3 before...");

        }
    }



    static class Target1 {


        public void foo() {
            System.out.println("target1 foo");
        }
    }
    static class Target2 {


        public void bar() {
            System.out.println("target1 bar");
        }
    }

}

set循环依赖

一级缓存,限制bean 在BeanFactory中只存一份,实现 Singleton scope

循环依赖图示,只有一级缓存的情况下
在这里插入图片描述

二级缓存解决:但是解决不了循环依赖里面有代理的情况 。
a先生成半成品代理对象,后依赖注入,但是b注入的时候是半成品的a,不是成品的代理对象a
在这里插入图片描述
三级缓存
在这里插入图片描述

构造方法循环依赖

在这里插入图片描述
解决思路:
在这里插入图片描述
第一种方式解决构造方法循环依赖


public class App60_1 {
    static class A{
        private static final Logger log = LoggerFactory.getLogger("A");
        private B b;
		//	使用@Lazy 让B后面再加载使用代理方式
        public A(@Lazy B b){
            log.debug("A(B b){}",b.getClass());
            this.b =b;
        }
        @PostConstruct
        public void init(){
            log.debug("init()");
        }
    }
    static class B{
        private static final Logger log = LoggerFactory.getLogger("B");
        private A a;
        public B(A a) {
            log.debug("B({})",a);
            this.a = a;
        }
        @PostConstruct
        public void init(){
            log.debug("init()");
        }

    }

    public static void main(String[] args) {
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean(A.class);
        context.registerBean(B.class);
        AnnotationConfigUtils.registerAnnotationConfigProcessors(context.getDefaultListableBeanFactory());
        context.refresh();
        System.out.println(context.getBean(B.class));
    }

}

第二种方式解决构造方法循环依赖

public class App60_1 {
    static class A{
        private static final Logger log = LoggerFactory.getLogger("A");
        private ObjectFactory<B> b;	
        //	构造方法注入 ObjectFactory 工厂或者他的子类ObjectProperty,可以延迟bean加载
        public A(ObjectFactory<B> b){
            log.debug("A(B b){}",b.getClass());
            this.b =b;
        }
        @PostConstruct
        public void init(){
            log.debug("init()");
        }
    }
    static class B{
        private static final Logger log = LoggerFactory.getLogger("B");
        private A a;
        public B(A a) {
            log.debug("B({})",a);
            this.a = a;
        }
        @PostConstruct
        public void init(){
            log.debug("init()");
        }

    }

    public static void main(String[] args) {
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean(A.class);
        context.registerBean(B.class);
        AnnotationConfigUtils.registerAnnotationConfigProcessors(context.getDefaultListableBeanFactory());
        context.refresh();
        System.out.println(context.getBean(B.class));
        System.out.println(context.getBean(A.class).b.getObject());
    }

}

第三种方式

public class App60_1 {
    static class A{
        private static final Logger log = LoggerFactory.getLogger("A");
        private Provider<B> b;
        // 注入 Provider 需要pom依赖
       //<dependency>
         //   <groupId>org.aspectj</groupId>
          //  <artifactId>aspectjweaver</artifactId>
           // <version>1.9.19</version>
//        </dependency>
        public A(Provider<B> b){
            log.debug("A(B b){}",b.getClass());
            this.b =b;
        }
        @PostConstruct
        public void init(){
            log.debug("init()");
        }
    }
    static class B{
        private static final Logger log = LoggerFactory.getLogger("B");
        private A a;
        public B(A a) {
            log.debug("B({})",a);
            this.a = a;
        }
        @PostConstruct
        public void init(){
            log.debug("init()");
        }

    }

    public static void main(String[] args) {
        GenericApplicationContext context = new GenericApplicationContext();
        context.registerBean(A.class);
        context.registerBean(B.class);
        AnnotationConfigUtils.registerAnnotationConfigProcessors(context.getDefaultListableBeanFactory());
        context.refresh();
        System.out.println(context.getBean(A.class).b.get());
        System.out.println(context.getBean(B.class));
    }

}

第四种方式:用@Scope方式,不推荐,就不看了了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/386133.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Navicat 现已支持 OceanBase 全线数据库产品

Navicat 作为 OceanBase 生态工具的合作伙伴&#xff0c;这是双方产品适配第三个里程碑。2022 年 7 月的首个里程碑&#xff0c;Navicat 实现了 OceanBase 社区版的功能性兼容。同年10 月&#xff0c;进一步实现了针对 OceanBase 企业版&#xff08; 兼容 MySQL 模式&#xff0…

一文图解|I/O 调度层

当我们使用 read() 和 write() 系统调用向内核提交读写文件操作时&#xff0c;内核并不会立刻向硬盘发送 I/O 请求&#xff0c;而是先将 I/O 请求交给 I/O 调度层进行排序和合并处理。经过 I/O 调度层加工处理后&#xff0c;才会将 I/O 请求发送给块设备驱动进行最终的 I/O 操作…

【强烈建议收藏:MySQL面试必问系列之慢SQL优化专题】

一.知识回顾 学习本篇文章之前呢&#xff0c;我们可以先看一下【强烈建议收藏:MySQL面试必问系列之SQL语句执行专题】&#xff0c;看完这篇文章再来学习本篇文章可谓是如虎添翼。好的&#xff0c;那我们也不讲太多的废话&#xff0c;直接开始。 二.如何做慢SQL查询优化呢&…

《uniapp基础知识》学习笔记Day38-(Period2)全局文件一些常用的配置

如果进行开发的话&#xff0c;首先要配置路由页面 page.json 页面路由 pages.json 文件用来对 uni-app 进行全局配置&#xff0c;决定页面文件的路径、窗口样式、原生的导航栏、底部的原生tabbar 等。 {"pages": [{"path": "pages/component/index…

Centos7搭建DHCP

1.简介DHCP服务器又叫动态主机协议&#xff0c;由服务器划分一段地址池&#xff0c;客户端地址池中获取IP地址及掩码等信息端口&#xff1a;UDP 67/68主配置文件&#xff1a;/etc/dhcp/dhcpd.conf租约时间文件&#xff1a;/etc/sysconfig/dhcpd2.简单搭建DHCP服务PS&#xff1a…

离线数据仓库项目--技术选择

文章目录&#xff08;一&#xff09;技术选型1&#xff09;数据采集工具2&#xff09;数据存储3&#xff09;数据计算4&#xff09;数据可视化&#xff08;二&#xff09;整体架构设计&#xff08;三&#xff09;服务器资源规划&#xff08;一&#xff09;技术选型 1&#xff…

MySQL索引事务

1.索引1.1概念索引是一种特殊的文件&#xff0c;包含着对数据表里所有记录的引用指针。可以对表中的一列或多列创建索引&#xff0c;并指定索引的类型&#xff0c;各类索引有各自的数据结果实现。&#xff08;这里只用通俗的语言和图片进行介绍&#xff09;1.2作用数据库中的表…

洗地机哪个牌子好?口碑最好的洗地机

选择洗地机&#xff0c;最关键的当然是清洁力度啦&#xff0c;这就要看洗地机的吸力如何了&#xff0c;一般情况下&#xff0c;吸力越大&#xff0c;越能够吸附顽固污渍&#xff0c;清洁力度就越好。然后杀菌功能也是必不可少的&#xff0c;毕竟是要清洁整个家的地面卫生&#…

Android 圆弧形 SeekBar

效果预览package com.gcssloop.widget;import android.annotation.SuppressLint;import android.content.Context;import android.content.res.TypedArray;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Matrix;import android.graph…

ViT(Vision Transformer) TNT(Transformer in Transformer)

ViT(Vision Transformer) ViT的结构 ViT将输入图片分为多个patch&#xff08;16x16&#xff09;&#xff0c;再将每个patch投影为固定长度的向量送入Transformer&#xff0c;后续encoder的操作和原始Transformer中完全相同。但是因为对图片分类&#xff0c;因此在输入序列中加…

论文复现-3

模型构建中的运算 数据集是CONLL03 这个数据集共有4种实体类型&#xff0c;所以&#xff0c;在做实体描述的embedding时&#xff0c;得到的语义表示的Tensor大小为 &#xff1a; 4*max_len, 具体指的是&#xff1a; type_input_ids: torch.LongTensor None, type_attention_m…

2023年中职组网络安全竞赛——web服务渗透测试解析

web服务渗透测试(100分) 题目如下: 解析如下: PS:任务环境可以私信博主,求个三连吧! 通过本地PC中的渗透测试平台KALI2020对靶机进行WEB渗透,找到页面内的文件上传漏洞并且尝试进行上传攻击,将文件上传成功后的页面回显字符串作为FLAG提交(如:点击超链接查看上传文…

Python自动化测试之requests库【发送json数据类型 】(六)

目录&#xff1a;导读 数据类型 application/json&#xff1a; application/x-www-form-urlencoded text/xml requests发送json 写在最后 我们都知道post请求中的body有4种数据类型&#xff0c;今天我们来写一篇关于requests请求json这种数据类型。 数据类型 我们都知道…

使用JSON.stringify的第三个参数,美化序列化后的值

事情是这样的&#xff0c;我在使用tiptap富文本编辑器&#xff0c;展示JSON代码&#xff0c;效果图肯定是这样的假设我有一个javascript对象如下const data {a: test }想要实现上面的效果&#xff0c;肯定需要使用JSON.stringifyconst editorData JSON.stringify(data)editor…

Linux中安装JDK8.跟学韩顺平

Linux中安装JDK8第16章Linux之JavaEE定制篇搭建JavaEE环境16.1 概述16.2安装JDK16.2.1安装步骤16.2.2测试是否安装成功第16章Linux之JavaEE定制篇搭建JavaEE环境 16.1 概述 如果需要在Linux下进行JavaEE的开发&#xff0c;我们需要安装如下软件 资料下载地址&#xff1a;百度…

【算法】BloomFilter概念和原理以及业务中的应用场景

思考&#xff1a;海量数据下去重&#xff0c;如果是非数值类型的话如何判断&#xff1f;1.什么是布隆过滤器 1970年由布隆提出的一种空间效率很高的概率型数据结构&#xff0c;它可以用于检索一个元素是否在一个集合中。 由只存0或1的位数组和多个hash算法, 进行判断数据 【一…

2023-03-03 mysql列存储-cpu占用100%-追踪思路

摘要: 最近在处理mysql列存储时, 发现在执行explain时, cpu占用达到了100%. 本文分析定位该问题的思路过程 现象: mysqld进程占用100%使用kill processlist终止会话, 无响应查看show processings; 发现一直在运行mysql> show processlist; +----+-----------------+-----…

图片服务器

文章目录一、项目简介二、功能及场景三、业务设计四、数据库设计准备图片表准备实体类五、API设计常用功能封装文件上传文件上传获取图片列表接口获取图片内容删除图片接口六、项目优化七、测试自动化测试测试用例一、项目简介 图片服务器&#xff1a;解决项目中插入图片的问题…

Java 运算符与类型转化

Java 运算符与类型转化 1 算术运算符 Java中的算术运算符主要有&#xff08;加&#xff09;、-&#xff08;减&#xff09;、*&#xff08;乘&#xff09;、/&#xff08;除&#xff09;、%&#xff08;求余&#xff09;&#xff0c;它们都是二元运算符。 2 自增和自减运算…

Day906.grant语句 -MySQL实战

grant语句 Hi&#xff0c;我是阿昌&#xff0c;今天学习记录的是关于grant语句的内容。 在 MySQL 里面&#xff0c;grant 语句是用来给用户赋权的。 不知道有没有见过一些操作文档里面提到&#xff0c;grant 之后要马上跟着执行一个 flush privileges 命令&#xff0c;才能使…