Spring实战笔记:Spring核心
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring实战笔记:Spring核心相关的知识,希望对你有一定的参考价值。
spring core
一.简介:
1.依赖注入(DI)
优点:解耦
Spring 通过应用上下文(Application Context)装载bean的定义,并把它们组装起来。
Spring应用上下文负责对象的创建和组装。
ClassPathXmlApplicationContext加载Spring上下文(ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("META-INF/spring/xxx.xml"),可通过context获取bean)
2. 应用切面
面向切面编程(aspect-Oriented programming,AOP):可以将遍布应用各处的功能解耦出来,形成可重用的组件。关注点的分离。
3.Bean
基于Spring的应用中,,应用对象生存于Spring容器中。Spring容器负责创建对象,装配对象,配置他们并管理他们的整个生命周期,从new到finalize()。
bean可以通过@Component("beanName")或@Named("beanName")来命名。其中@Named是Java依赖注入规范中提供的。
Spring容器不只有一个,Spring自带了多个容器实现,可以归为两种不同类型:
--bean工厂:最简单的容器,提供基本DI支持;
--应用上下文:基于BeanFactory构建,并提供应用框架级别的服务。(应用较多)
BeanFactory和FactoryBean的区别( https://www.cnblogs.com/redcool/p/6413461.html):
BeanFactory是一个工厂类,用于管理Bean的一个工厂。BeanFactory是IOC容器的核心接口,负责实例化,定位,配置应用程序中的对象及建立这些对象间的依赖。
FactoryBean是实现了FactoryBean<T>接口的Bean。根据该Bean的ID从BeanFactory中获取的实际上是FactoryBean的getObject()返回的对象,而不是FactoryBean本身,若要获取FactoryBean本身需要在id前面加一个&符号。
二.装配Bean
将组件扫描得到的bean和他们的依赖装配在一起
1.自动扫描组件
@Controller控制器:注入服务
@Service服务:注入Dao
@Repository Dao:实现Dao访问
@Component:把普通的POJO实例化到Spring容器中,相当于配置文件中的<bean id="" class=""/>
@Controller,@Service,@Repository,@Component注解的类,并把这些类纳入进Spring容器中进行管理。
引入Component的扫描组件:
其中base-package是需要扫描的包(含所有子包)
<context:component-scan base-package="com.best"/>
可以使用@Configuration替代xml配置,@ComponentScan(basePackages={"",""})指定扫描组件的包及子包下带有@Component注解的类。@ComponentScan默认扫描所在类的包及子包。
@Controller:用于标注控制层组件
@Service:用于标注业务层组件
@Repository:用于标注数据访问层组件,即DAO组件
@Component:泛指组件,当组件不好归类时,可使用该注解进行标注。
@Controller,@Service,@Repository,@Component注解的类,并把这些类纳入进Spring容器中进行管理。
2.自动装配
@Autowired可以用在构造方法和类的方法上。spring会满足方法参数上所声明的依赖。
-- 如果没有匹配的bean:在应用上下文创建的时候,Spring会抛出异常,为避免异常可以使用@Autowired(required=false)
-- 有匹配的bean时:若使用了@Autowired(required=false),在代码没有进行null检查时,这个处于未装配状态的属性可能会抛出NullPointException。
@Inject也可以完成自动装配,是Java依赖注入规范中提供的。
三.高级装配
@Profile("dev") -----为dev环境 profile装配的bean
使用Profile首先要将所有不同的bean定义整理到一个活多个Profile中,在将应用部署到每个环境时,要确保对应的Profile处理激活(active)状态,只有当规定的profile被激活时,相应的bean才会被创建。
使用@Profile注解指定某个bean属于哪一个Profile。
激活profile方法:
-- 作为DispatcherServlet的初始化参数;
-- 作为WEB应用的上下文参数;
-- 作为JNDI条目;
-- 作为环境变量;
-- 作为JVM的系统属性;
-- 在集成测试类上,使用@ActiveProfiles注解设置:@ActiveProfiles("dev")
@Conditional(xxxCondition.class) -----条件化地创建bean
可以用到带有@Bean注解的方法上,如果给定条件计算结果为true,就会创建这个bean,否则这个bean将会被忽略。
设置给Conditional的类可以是任意实现了Condition接口的类型,这个接口只需提供matches()方法的实现即可。matches()方法返回true就会创建带有 @Conditional注解的bean。
@Autowired
使用自动装配让Spring完全负责将bean引用注入到构造参数和属性中,能够减少装配应用程序组件时所需的显示配置的数量。
如果有多个bean能够匹配结果时Spring会抛出NoUniqueBeanDefinitionException。
此时可以将可选bean中的某一个设为首选(@Primary,Primary与@Component或@Bean一起使用)的bean 或使用限定符(@Qualifier("xxxbeanName"),Qualifier与@Autowired一起使用)来帮助Spring将可选的bean范围缩小到只有一个bean。
Qualifier也可以与@Component或@Bean一起使用,为某一个bean设置beanName即创建自定义的限定符,以防止bean类名修改导致找不到Qualifier指定beanName。
1.bean的作用域
默认情况下,Spring应用上下文中所有bean都是作为一单例(singleton)的形式创建的。即不管给定的一个bean被注入到其他bean多少次,每次所注入的都是同一个实例。
当所使用的类是异变的(mutable),他们会保持一些状态,此时重用是不安全的。
Spring定义了多种作用域,可以基于这些作用域创建bean:
-- 单例(Singleton):在整个应用中,只创建bean的一个实例;
-- 原型(Prototype):每次注入或通过Spring应用上下文获取的时候,都会创建一个bean实例;
-- 会话(Session):在Web应用中,为每个会话创建一个bean实例;
-- 请求(Request):在Web应用中,为每个请求创建一个bean实例。
单例是默认作用域,如果要选择其他作用域,要使用@Scope注解,与@Component或@Bean一起使用:
-- 原型:@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)或@Scope("prototype")
-- 会话:@Scope(value=WebApplicationContext.SCOPE_SESSION, proxyMode=ScopedProxyMode.INTERFACES)
-- 请求:@Scope(value=WebApplicationContext.SCOPE_REQUEST, proxyMode=ScopedProxyMode.INTERFACES)
当一个会话或者请求作用域的bean(BeanSession)要注入到单例作用域的bean(BeanSingle)中时,会出现一些问题:
-- BeanSingle在Spring应用上下文加载的时候创建,此时Spring会试图将BeanSession注入到BeanSingle中,而此时BeanSession还不存在(当有用户进入系统,创建会话后才会被创建)。
-- 系统中可能会存在多个BeanSession,大多数情况下我们不希望注入一个固定的BeanSession到BeanSingle中,而是当前Session中的那个。
为了解决这个问题,Spring不会将实际的BeanSession注入到BeanSingle中去,而是注入一个BeanSession的代理。这个代理会暴露出和BeanSession相同的方法,BeanSingle会认为它是一个普通的BeanSession。
@Scope注解有一个proxyMode属性,用于配置代理。有两种方式:
-- ScopeProxyMode.INTERFACES,这表明该代理会实现BeanSession接口,并将调用 委托给具体的实现bean。这种方法要求BeanSession是一个接口。
-- ScopeProxyMode.TARGET_CLASS,这表明Spring会使用CGLib生成目标类的扩展的方式来创建代理。这种方式适用于BeanSession是具体的类。
2.运行时值注入
依赖注入通常是指将一个bean引用注入到另一个bean的属性或构造器参数中。它通常来讲是指将一个对象与另一个对象进行关联。
依赖注入能够将组件及其协作的其他组件解耦。
bean的装配另一个方面是将一个值注入到bean的属性或构造器参数中。
Spring的两种运行时求值的方式:
-- 属性占位符(Property placeholder):较简单;
-- Spring表达式语言(SpEL):较强大。
占位符的形式为使用"${...}"包装的属性名称,使用XML配置Spring context命名空间:
<context:property-placeholder location="classpath*:redis.properties,classpath*:shiro.properties" ignore-unresolvable="true"/> <!--remember Cookie--> <bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie"> <constructor-arg value="${shiro.cookie.name.prefix}-rememberMe"/> <property name="httpOnly" value="true"/> <property name="maxAge" value="2592000"/> </bean>
Spring表达式语言能够以一种强大简洁的方式将值装配到bean属性和构造器参数中,在这个过程中所使用的表达式会在运行时计算得到值。
SpEL拥有如下特性:
-- 使用bean的ID来引用bean;
-- 调用方法和访问对象的属性;
-- 对值进行算术、关系和逻辑运算;
-- 正则表达式匹配;
-- 集合操作。
SpEL表达式要放到"#{...}"之中:
<bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager"> <!– rememberMe cookie加密的密钥 建议每个项目都不一样 默认AES算法 密钥长度(128 256 512 位)–> <property name="cipherKey" value="#{T(org.apache.shiro.codec.Base64).decode('GHxH6G3LFh8Zb3NwoRgfFA==')}"/> <property name="cookie" ref="rememberMeCookie"/> </bean>
以上是关于Spring实战笔记:Spring核心的主要内容,如果未能解决你的问题,请参考以下文章