当前位置: 首页 > news >正文

spring实战第四版01

spring自带了很多容器的实现,,总的分为两类:

  • bean工厂 : 基本的DI支持
  • ApplicationContext: 应用上下文,,应用框架级别的服务,,有更多的特性,比如属性文本解析,事件发布
    • AnnotationConfigApplicationContext
    • AnnotationConfigWebApplicationContext
    • ClassPathXmlApplicationContext
    • FileSystemXmlApplication
    • XmlWebApplicationContext
spring生命周期

在这里插入图片描述

  1. 实例化
  2. 填充属性
  3. 调用BeanNameAware的setBeanName()方法,,如果bean实现了BeanNameAware,,那么spring就会将bean的id传递给setBeanName()方法作为参数
  4. 调用BeanFactoryAware的setBeanFactory()方法,,,可以感知BeanFactory
  5. 调用ApplicationContextAware的setApplicationContext()方法,,,可以感知ApplicationContext
  6. 调用BeanPostProcessor的预初始化方法,,如果实现了这个接口,,就会去调他的postProcessBeforeInitialization()方法
  7. 调用InitializingBean的afterPropertiesSet()方法:spring将调用他们的afterPropertiesSet()方法,如果bean使用init-method声明了初始化方法,该方法也会被调用
  8. 调用自定义初始化方法 init-method
  9. 调用BeanPostProcessor的初始后方法,,spring将调用postProcessAfterInitialization方法,初始化后方法
  10. bean可以使用了
  11. 容器关闭
  12. 调用Disposable的destroy()方法,,如果bean使用destroy-method声明了销毁方法,同样也会调用
  13. 调用自定义销毁方法 destroy-method
  14. 结束
自动化装配

spring中可以自己注册bean,但是一般都是自动化装配的,,spring中的自动化装配有两种方式:

  • 组件扫描 component scanning:spring会自动发现应用上下文中所创建的bean
  • 自动装配 autowiring: spring会自动满足bean之间的依赖

组件扫描默认不启用: 需要配置@ComponentScan。。或者xml配置<context:component-scan>

spring中测试
   <dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>6.1.12</version></dependency>
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = TestConfig.class)
public class DemoTest {@AutowiredUser user;@Testpublic void test(){System.out.println("user = " + user);}
}
  • @ContextConfiguration(classes=TestConfig.class) : 这个可以自定义测试的配置文件,手动指定xml/Java config,,主要用于传统的spring项目测试,,非boot
  • @SpringBootTest : 自动加载@SpringBootApplication
spring中bean的装配

bean的装配分为两种:

  1. 隐式的装配
  2. 显示的装配
隐式的装配

@ComponentScan的属性

  • basePackage
  • baskPackageClasses : 设置的数组中包含了类,,这些类所在的包,,会作为组件扫描的基础包,可以创建一个用来扫描的空标记接口(marker interface)

@Autowired

@Autowired这个注解不仅能用在构造器上,还能用在setter方法上,,并且能用在类的任意方法上,spring都会尝试满足方法参数上所声明的依赖,,,如果没有bean会报错,,如果不能确定唯一的bean也会报错,,,,
@Autowired的属性:
- required : 设置为false,找不到不会报错,,但是在启动的时候就发现不了错误了,,执行到那一块代码可能会因为没有注入对象而空指针

@Autowired@Inject,在大多数场景下,,可以互换
@Inject:这个注解来源于 Java依赖注入规范,,该规范同时还定义了@Named注解,,
@Named注解 和 @Component,在大多数场景下,可以互换

但是这种打注解注入的方式,,注入不了第三方组件,,,就需要显示的装配,,,

显示的装配

显示的装配可以用java或者 xml来装配
xml装配bean,,如果不给id,,系统默认会使用全限定类名#0 ,,就是全限定类名+序号,,如果是第一个就是#0,如果有多个,,序号往后累加


@Primary 和 限定符Qualifier(想要注入bean的id)

Environment

PropertySourcesPlaceholderConfigurer: 这个类的对象,能够基于spring environment及其属性源来解析占位符

@PropertySource("classpath:db.properties"): 这个注解会将这个配置加载到spring的Environment中

@Configuration
// 这个属性文件会加载到spring的Environment中,,,
@PropertySource("classpath:db.properties")
public class ExpressiveConfig {@AutowiredEnvironment env;//?????@Value("#{systemProperties['db.username']}")private String username;@Value("#{T(System).currentTimeMillis()}")private Long time;@Beanpublic DataSource dataSource(){System.out.println("username = " + username);System.out.println("time = " + time);String url = env.getProperty("db.url");System.out.println("env.getProperty(\"db.url\") = " +url);Integer age = env.getProperty("user.age", Integer.class, 30);System.out.println("age = " + age);Integer age02 = env.getProperty("user.age02", Integer.class, 30);System.out.println("age02 = " + age02);// 检测某个属性是否存在boolean b = env.containsProperty("user.age02");System.out.println("b = " + b);// 返回激活的profileString[] activeProfiles = env.getActiveProfiles();// 默认的profileString[] defaultProfiles = env.getDefaultProfiles();System.out.println("activeProfiles = " + Arrays.toString(activeProfiles));System.out.println("defaultProfiles = " +  Arrays.toString(defaultProfiles));// 是否支持某个profileboolean b1 = env.acceptsProfiles("prod");System.out.println("b1 = " + b1);DataSource ds = new DataSource();ds.setUrl(url);return ds;}
}

env.acceptsProfiles('prod') : 检测环境中是否有 prod的profile

profile多环境切换

spring.profiles.activespring.profiles.default ,如果没有设置spring.profiles.active那么spring会查找spring.profiles.default的值,,,如果这两个都没有设置,那么spring只会创建那些没有定义在profile中的bean,,,,这两个属性都是复数,,可以激活多个profile,,,列出多个profile,逗号分隔

多种方式来设置这两个属性:

  • 作为DispatcherServlet的初始化参数
  • 作为web应用的上下文参数
  • 作为JNDI条目
  • 作为环境变量
  • 作为JVM的系统属性
  • 在集成测试类上,使用@ActiveProfiles注解设置
@Conditional

profile底层是@Conditional,

public class MyCondition implements Condition {@Overridepublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {return false;}
}

这个方法里面的参数是:

  • ConditionContext

    这个是个容器,,可以获取一些对象。比如:

    • BeanDefinitionRegistry : 可以用来检查bean定义
    • ConfigurableListableBeanFactory : 可以用来检查bean是否存在,检查bean的属性
    • Environment : 可以用来检查环境变量是否存在,,以及环境变量对应的值
    • ResourceLoader : 返回ResourceLoader所加载的资源
    • ClassLoader : 可以用来加载并检查类是否存在
  • AnnotatedTypeMetaddata : 能够让我们检查到,,带有@Bean注解的方法上,,还有什么其他的注解

scope的作用域

spring默认的作用域是singleton,同一个实例,,但是有些时候,,你所使用的类是易变的mutable,,他们可能会保持一些状态,,,,因此,重用是不安全的

scope作用域:

  • 单例singleton : 整个应用中,只创建bean的一个实例
  • 原型prototype : 每次注入或者通过spring应用上下文获取的时候,都会创建一个新的bean实例
  • 会话session: 在web应用中,为每个会话创建一个bean实例
  • 请求request: 在web应用中,为每个请求创建一个bean实例
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Scope("prototype")

商城中,如果购物车对象是单例的话,那么会导致所有用户都会向同一个购物车添加商品,,,另一方面,如果购物车是原型作用域,,那么在应用中某一个地方往购物车中添加商品,在应用的另一个地方可能就不可用了,,prototype总是获取一个新的bean

所以购物车用会话作用域,是最为合适的:


// proxyMode = ScopedProxyMode.INTERFACES : 这个属性解决了 将会话或者请求作用域的bean注入到单例bean中所遇到的问题
@Scope(value= WebApplicationContext.SCOPE_SESSION,proxyMode = ScopedProxyMode.INTERFACES)

为什么要添加这个???proxyMode = ScopedProxyMode.INTERFACES,,因为spring默认是单例的,,如果一个类中@Autowired注入了这个 session作用域的bean,,,而session作用域的bean,只会在用户访问应用之后才会生成,,容器初始化的时候,是没有这个bean的,,所以会报错,,,配置了
proxyMode=ScopedProxyMode.INTERFACES之后,,spring不会直接创建 ShoppingCart实例,,而是会注入一个 ShoppingCart的代理,,这个代理会暴露跟 ShoppingCart一样的方法,,,当用户访问系统后,,,代理会对其进行懒解析,,,并将调用委托给真正的ShoppingCart的Bean

如果这个ShoppingCart是接口就使用proxyMode=ScopedProxyMode.INTERFACES
如果这个ShoppingCart是一个具体的类,,spring就会使用cglib生成基于类的代理,,就使用proxyMode=ScopedProxyMode.TARGET_CLASS,来表明要以生成目标类扩展的方式创建代理

在这里插入图片描述

spring的运行时求值

spring提供了两种在运行时求值的方式:

  • 属性占位符 Property placeholder
  • spring表达式语言 SpEL : spring expression language
spring表达式特性
  • 使用bean的id来引用bean
  • 调用方法和访问对象的属性
  • 对值进行算数,关系,和逻辑运算
  • 正则表达式匹配
  • 集合操作

SpEL需要放到#{...}之中,,属性占位符需要放到${...}之中
用法:

  • #{beanId.属性名字} : 获取指定id的bean的属性值
  • #{systemProperties['user.age']} : 通过systemProperties对象引用系统属性
  • T(java.lang.Math): 在SpEL中访问类作用域的方法和常量的话,,使用T(),比如T(System).currentTimemillis()

使用场景:

  • spring security的安全限制规则
  • thymeleaf模板中使用SpEL表达式引用模型数据
http://www.xdnf.cn/news/647569.html

相关文章:

  • 【SpringBoot】从零开始全面解析Spring IocDI (二)
  • Windows系统如何查看ssh公钥
  • 第十一天 5G切片技术在车联网中的应用
  • ORM++ 封装实战指南:安全高效的 C++ MySQL 数据库操作
  • window 显示驱动开发-视频内存的直接交替(二)
  • 黑马点评Reids重点详解(Reids使用重点)
  • P2015 二叉苹果树
  • C#高级:Winform桌面开发中CheckedListBox的详解
  • 泰迪杯特等奖案例深度解析:基于三维点云与深度学习的复杂零件装配质量检测系统设计
  • 基于AOD-Net与GAN的深度学习去雾算法开发
  • 【Spring】Spring AI 核心知识(一)
  • LSTM三个门控机制详解
  • 电池预测 | 第28讲 基于CNN-GRU的锂电池剩余寿命预测
  • 对Spring IOC与AOP的理解
  • 深度学习在图像识别中的创新应用及其挑战
  • Innodb底层原理与Mysql日志机制深入刨析
  • 如何利用 Spring Data MongoDB 进行地理位置相关的查询?
  • vue+cesium示例:3Dtiles三维模型高度调整(附源码下载)
  • [IMX] 08.RTC 时钟
  • BGP笔记的基本概要
  • Linux进程通信之管道机制全面解析
  • Python基于Django的主观题自动阅卷系统【附源码、文档说明】
  • ​《分布式年夜》
  • export、export default和module.exports有什么区别
  • RocketMQ 深度解析:消息中间件核心原理与实践指南
  • 【Linux】进程 信号的产生
  • Vue修饰符全解析
  • ISO 26262-5 区分失效模式
  • OWASP Juice-Shop靶场(⭐⭐)
  • (1-6-2)Java泛型