Spring
什么是springDI依赖注入AOP(面向切片编程)什么是springSpring 是一个开源框架,是为了解决企业应用程序开发复杂性而创建的。Spring对应的关键词是DI(依赖注入)与AOP(面向切面编程),可以认为是一个以DI和AOP为核心Java Web一站式的集成(粘合)框架。DI和AOP能够让代码更加简单,具有良好的松耦合特性和可测试性,极大地简化开发...
文章目录
Spring
定义
Spring是分层的JavaSE/EE full-stack(一站式) 基于容器
的轻量级开源框架
,是为了解决企业应用程序
开发复杂
性而创建的。核心特性可以用于开发任何 Java 应用程序
。Spring的出现是为了取代EJB(Enterprise JavaBean)的臃肿、低效、脱离现实。
SUN提供的EE的三层结构:
- web层。Struts2是web层基于MVC设计模式框架.
- 业务层。
- 数据访问层(持久层,集成层)。Hibernate是持久的一个ORM的框架.
Spring框架有对三层的一站式解决方案:
- web层:Spring MVC
- 持久层:JDBC Template
- 业务层:Spring的Bean管理
Spring的核心
Spring容器
Spring有两个核心接口:BeanFactory和ApplicationContext,其中ApplicationContext是BeanFactory的子接口。他们都可代表Spring容器,Spring容器是生成Bean实例的工厂
,并且管理容器中的Bean
。
基于 Spring 的应用中,所有的对象(即bean)生存于 Spring 容器,Spring 负责创建、装配、配置并管理这些bean的整个生命周期。
DI依赖注入
DI(依赖注入)也称为IoC(控制发转)用于管理Java对象之间的依赖关系.
其基本概念是:不创建对象,但是描述创建它们的方式。在代码中不直接与对象和服务连接,但在配置文件中描述哪一个组件需要哪一项服务。容器 (在 Spring 框架中是 IOC 容器) 负责将这些联系在一起。
AOP(面向切片编程)
AOP用于解耦业务代码和公共服务代码(如日志,安全,事务等)。
AOP术语
- 通知(Advice) :就是你想要的功能,用方法实现的功能,也就是上说的安全、事物、日子等。你先把功能用方法给先定义好,然后再想用的地方用一下。包含Aspect的一段处理代码。
- 连接点(JoinPoint) :就是spring允许你把通知(Advice)放在的地方,那可就真多了,基本每个方法的前、后(两者都有也行),或抛出异常是时都可以是连接点,spring只支持方法连接点。其他如AspectJ还可以让你在构造器或属性注入时都行,不过那不是咱们关注的,只要记住,和方法有关的前前后后都是连接点。
- 切入点(Pointcut): 是上面说的连接点的基础上,来定义切入点,你的一个类里,有15个方法,那就有几十个连接点了对吧,但是你并不想在所有方法附件都使用通知(使用叫织入,下面再说),你只是想让其中几个,在调用这几个方法之前、之后或者抛出异常时干点什么,那么就用切入点来定义这几个方法,让切点来筛选连接点,选中那几个你想要的方法。
- 切面(Aspect) :是通知和切入点的结合。现在发现了吧,没连接点什么事,连接点就是为了让你好理解切点搞出来的,明白这个概念就行了。通知说明了干什么和什么时候干(什么时候通过方法名中的befor,after,around等就能知道),二切入点说明了在哪干(指定到底是哪个方法),这就是一个完整的切面定义。
- 引入(introduction) :允许我们向现有的类添加新方法属性。这不就是把切面(也就是新方法属性:通知定义的)用到目标类中吗。
- 目标(target) :引入中所提到的目标类,也就是要被通知的对象,也就是真正的业务逻辑,他可以在毫不知情的情况下,被咋们织入切面。二自己专注于业务本身的逻辑。
- 代理(proxy) :怎么实现整套AOP机制的,都是通过代理,这个一会儿给细说。
- 织入(weaving): 把切面应用到目标对象来创建新的代理对象的过程。
Spring配置方式
通过配置Spring告诉容器需要加载哪些Bean和如何装配这些Bean。
通过配置文件
- Spring的核心框架提供了10个命名空间配置
- Spring的属性注入有两种方式:构造器注入和set方法注入
配置文件含义
关于图片的补充:
- 为类的非集合类型成员变量进行注入:有构造器注入和set注入(需要有set方法)两种方法。其中构造器注入通过constructor-arg标签,set注入通过property标签。
- 创建Bean:可以通过构造函数,也可以通过设置bean标签的factory-method属性,通过静态方法创建。
//使用factory-method属性:允许我们调用一个指定的静态方法代替构造函数创建一个实例。
<bean> id="duke"
class="com.springinaction.springidol.Juggler">
factory-method="getInstance"/>
</bean>
--------------------------------------------------------------------
//<constructor-arg> 元素:构造函数注入,让Spring调用对应的构造器实现成员变量赋值,否则使用默认空参构造器
<bean> id="duke" class="com.springinaction.springidol.Juggler">
<constructor-arg value="15">
</bean>
--------------------------------------------------------------------
<beans>的default-init-method和default-destroy-method属性为所有Bean设置了共同的初始化和销毁方法。
--------------------------------------------------------------------
<bean>内部可以包含内部Bean,可以通过构造器和set方法注入:
1、通过set方法注入
<bean id="saxophone" class="com.spring.test.setter.Saxophone"/>
</bean>
<bean id="kenny" class="com.spring.test.setter.Instrumentalist">
<property name="age" value="25" />
<property name="instrument">
<bean class="com.spring.test.setter.Saxophone"/>//将bean赋给instrument,这个bean专属于Bean kenny,和上面id="saxophone"的Bean不是一个Bean
</property>
</bean>
2、通过构造器注入
<bean id="kenny" class="com.spring.test.setter.Instrumentalist">
<constructor-arg value="30"/>
<constructor-arg>
<bean class="com.spring.test.setter.Saxophone"/>
</constructor-arg>
</bean>
上面的构造器注入对应的构造函数是:
public Instrumentalist(int age,Instrument instrument){
this.age = age;
this.instrument = instrument;
}
装配集合属性
元素 | 描述 | 可以装配的类型 |
---|---|---|
<list> | 允许重复 | 任何 java.util.Collection 的实现或数组 |
<set> | 不允许重复 | 任何 java.util.Collection 的实现或数组 |
<msp> | 名称和值可以是任意类型 | java.util.Map |
<props> | 名称和值必须是String类型 | java.util.Properties |
- 具体配置代码可以参见上面的图,另外补充:<msp> 中key为Bean引用的时候,需要用
key-ref
指定,而非key。
通过SpEL(Spring表达式)装配Bean的属性
有些属性在运行时才知道,此时需要运行期执行的表达式将值装配到Bean的属性或构造函数中。通过SpEL可以完成传统Spring装配方式难以做到的事情:
- 调用方法和访问对象的属性;
- 对值进行算数、关系和逻辑运算;
- 正则表达式匹配;
- 集合操作。
SpEL表达式要放到#{ }
之中,具体而言:
- 表示字面值
<bean id = "yoona" class = "com.sjf.bean.Student">
<property name="age" value="#{24}"/>
<property name="school" value="#{'西电'}"/>//字面量为字符串时,里面单引号外面双引号,反之亦可
<property name="name" value="my name is #{'yoona'}"/>
<property name="weight" value="#{120.4}"/>
<property name="sex" value="#{true}"/>
</bean>
- 引用Bean、属性和方法
//引用Bean---------------------------------------------
<property name="school" ref="xidianSchool"/>
//上面用SpEL可以表示如下。注意,用的还是value!
<property name="school" value="#{xidianSchool}"/>
//引用Bean属性---------------------------------------------
property name="address" value="#{xidianSchool.location}"/>
//引用Bean方法---------------------------------------------
<property name="address" value="#{xidianSchool.getLocation()}"/>
//如果getLocation() 返回一个null 值, 那么SpEL 表达式求值时会抛出一个NullPointerException 异常。
//为避免抛出空指针异常,使用null-safe 存取器(?.)。如果如果getLocation() 返回一个null 值,SpEL不会再调用getCity()方法。
<property name="address" value="#{xidianSchool.getLocation()?.getCity()}"/>
- 操作类
//在SpEL 中,使用T() 运算符返回类对象,从而调用类的静态方法和常量
<property name="pi" value="#{T(java.lang.Math).PI}"/>
<property name="randomNumber" value="#{T(java.lang.Math).random()}"/>
- 运算
- 在SpEL 中筛选集合
- 访问集合成员
[]
<property name="school" value="#{schools[数字常量或者表示式]}"/>
- 查询集合成员
.?[] 或 .^[] 或 .$[]
//从学校集合中查询位于西安的学校
<property name="likeSchool" value="#{schools.?[location == '西安']}"/>
//从集合中查询出第一个匹配项
<property name="school" value="#{schools.^[location == '山东']}"/>
//从集合中查询出最后一个匹配项
<property name="school" value="#{schools.$[location == '山东']}"/>
- 投影集合
.![]
//从集合的每一个成员中选择特定的属性放入一个新的集合中
//将所有学校的姓名作为成员,放入visitedSchool集合中
<property name="visitedSchool" value="#{schools.![name]}"/>
通过注解
Bean的作用域
当通过Spring容器创建一个Bean实例时,不仅可以完成Bean实例的实例化,还可以为Bean指定特定的作用域。Spring支持如下5种作用域:
-
singleton:默认,单例模式,在整个Spring IoC容器中,使用singleton定义的Bean将只有一个实例
-
prototype:原型模式,每次通过容器的getBean方法获取prototype定义的Bean时,都将产生一个新的Bean实例
-
request:对于每次HTTP请求,使用request定义的Bean都将产生一个新实例,即每次HTTP请求将会产生不同的Bean实例。只有在Web应用中使用Spring时,该作用域才有效
-
session:对于每次HTTP Session,使用session定义的Bean都将产生一个新实例。同样只有在Web应用中使用Spring时,该作用域才有效
-
globalsession:每个全局的HTTP Session,使用session定义的Bean都将产生一个新实例。典型情况下,仅在使用portlet context的时候有效。同样只有在Web应用中使用Spring时,该作用域才有效
p命名空间和c命名空间
使用p-namesapce和c-namespace可以简化bean的定义。
-
p-namespace的作用就是使用xml中的元素属性取代节点来定义bean的属性。
//普通set注入: <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="person" class="Person"> <property name="name" value="Tom"/> <property name="age" value="20"/> </bean> <bean id="messageHandler" class="MessageHandler"> <property name="messageService"> <ref bean="messageService" /> </property> </bean> </beans> //使用p-namespace <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" //增加了一行声明 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="person" class="Person" p:name="Tom" p:age="20"/> //简化为一行 <bean id="messageHandler" class=“MessageHandler” p:messageService-ref=“messageService”/> //加上-ref后缀即表示是对一个bean的引用 </beans>
-
类似的,c-namespace的作用就是简化构造器方式注入方式
//普通构造器注入 <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:c="http://www.springframework.org/schema/c" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="person" class="Person"> <constructor-arg name="name"> <value>Tom</value> </constructor-arg> <constructor-arg name="age" value="20"/> </bean> <bean id="messageHandler" class="MessageHandler"> //一般类型赋值 <constructor-arg name="messageService" ref bean="messageService"/> //对象赋值 </bean> </beans> //使用c-namespace <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:c="http://www.springframework.org/schema/c" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="person" c:name="Tom" c:age="20"/> <bean id="messageHandler" class="MessageHandler" c:messageService-ref="messageService"/> </beans>
如何使用Bean
- 创建上下文
- 使用getBean方法获取bean
最小化Spring XML配置
随着应用的不断发展,我们将不得不编写越来越复杂的XML配置,为此Spring提供了自动装配和自动检测来帮助我们减少XML的配置数量。
Bean的自动装配
让Spring自动识别如何装配Bean的依赖关系,有助于减少甚至消除配置<property>元素和<constructor-arg>元素
-
4中类型的自动装配:
利用<beans>属性default-autowire
为所有Bean设置自动装配类型,默认为none,表示都不使用自动装配。
利用<bean>元素的autowire
属性来覆盖<beans>的默认自动装配策略,设置某个Bean的自动装配类型。
即使设置了自动装配,我们还是可以通过显式配置来指定装配的值,而忽略自动装配。 -
byName——把与
Bean的属性名
具有相同名字
(或者id
)的其他Bean自动装配到Bean的对应属性中。如果没有跟属性的名字相匹配的Bean,则该属性不进行装配。
//手动装配 <bean id="saxophone" class="com.roger.spring.beans.Saxophone" /> <bean id="kenny" class="com.roger.spring.beans.Instrumentalist"> <property name="song" value="Jingle Bells" /> <property name="instrument" ref="saxophone" /> </bean> //自动装配:自动装配 kenny 的 instrument 属性 <bean id="instrument" class="com.roger.spring.beans.Saxophone" /> <bean id="kenny" class="com.roger.spring.beans.Instrumentalist" autowire="byName"> <property name="song" value="Jingle Bells" /> </bean>
-
byType——把与Bean的属性具有
相同类型
的其他Bean自动装配到Bean的对应属性中。如果没有跟属性的名字相匹配的Bean,则该属性不进行装配;
如果找到多个匹配的Bean则抛出异常。即应用只允许存在一个Bean与需要自动装配的属性类型相匹配。- 解决装配歧义的问题:
设置一个首选: 将想选的Bean的<bean>中primary属性设为true(所有Bean 默认为true)
取消其他符合条件的Bean的资格:将其他的Bean的<bean>中primary属性设为false
- 解决装配歧义的问题:
-
constructor——把与Bean的构造器入参具有
相同类型
的其他Bean自动装配到Bean构造器的对应入参中。在Bean声明中,不需要<constructor-arg>元素了。具有和byType自动装配相同的局限和解决办法。
-
autodetect——首先尝试使用constructor进行自动装配。如果没有发现与构造器相匹配的Bean时,再尝试使用byType进行自动装配。
使用注解装配Bean
使用注解方式允许更细粒度
的自动装配,可以选择性地
标注某一个属性来对其应用自动装配。
-
Spring容器
默认禁用注解装配
,所以需要先在xml配置中启用注解。最简单的启用方式为利用context命名空间中<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 http://www.springframework.org/schema/beans/spring-beans.xsd http:..www.springframework.org/schema/context http:..www.springframework.org/schema/context/spring-context.xsd"> <context:annotation-config /> </beans>
-
Spring支持集中不同的用于自动装配的注解
-
Spring自带的
@Autowired
注解(默认是通过byType
方式进行自动装配)1、标注属性:可以配置任何成员变量,包括私有的 @Autowired private Instrument instrument; 2、标注方法:可以配置任何成员方法,包括没有set方法的一般方法和构造器 @Autowired public void setInstrument (Instrument instrument){ this.instrument = instrument } 3、一些补充 a、默认情况下,这个注解标识的属性或参数必须是可装配的。没有Bean装配到,就会报NoSuchBeanDefinitionException。这个时候可以设置required=false来设置自动装配是可选的。没有匹配到Bean就会为null。 @@Autowired(required=false) b、有可能spring找到了多个满足条件的Bean,通过@Qualifier注解将范围缩小。相当于把byType转为了byName。 @Qualifier("guita")//尝试将id为"guita"的bean注入
-
JSR-330的
@Inject
注解- 这个注解和@Autowired一样可以自动装配,可以装配属性,方法,构造器。但是没有required属性所以装配的Bean必须存在,不存在会报错。
- @Autowired的@Qualifier与@Inject的@Named对应。 @Qualifier注解缩小Bean的选择范围(默认使用Bean的id),@Named通过Bean的Id标识可选择的Bean
-
JSR-250的
@Resource
注解
@Resource装配顺序- 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常
- 如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常
- 如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常
- 如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配;
-
使用
@Value
在注解注入中使用表达式@Value("jack")//装配静态值 private String name; @Value("#{abc.name}")//动态装配 private String name;
Bean的自动检测
比自动装配更进一步,让Spring能够自动识别哪些类需要被配置成Spring Bean,从而减少对<bean>元素的使用。
- 需要先启用注解:
<context:component-scan>
。还可以通过<context:component-scan>元素的base-package
属性指定的包及其所有子包。<?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 http://www.springframework.org/schema/beans/spring-beans.xsd http:..www.springframework.org/schema/context http:..www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="com.roger.spring.beans"> </context:component-scan> </beans>
- 默认情况下,<context:component-scan>查找使用构造型(stereotype)注解所标注的类。这些特殊注解如下:
-
@Component
——通过的构造型注解,标识该类为Spring组件- Spring扫描发现@Component注解所标注的类,并自动地将它注册为Spring Bean,Bean的ID默认为无限定类名(如:Person Bean的id为person)
- 也可以使用@Component(“Roger”)方式来指定Bean的id。
-
@Controller
——标识将该类定义为Spring MVC controller -
@Repository
——标识将该类定义为数据仓库 -
@Service
——标识将该类定义为服务 -
使用@Component标注的任意自定义注解
-
<context:component-scan>下面还有子元素<context:include-filter>和<context:exclude-filter>。
-
只是用<onctext:component-scan>的情况下,spring只会去找基于注解的组件。但是还要包含一个没有注解的接口的所有实现类要怎么办。就是用
<context:include-filter>
。<context:component-scan base-package="包"> //派生与Instrument的所有类自动注册为SpringBean <context:include-filter type="assignable" expression="com.springinaction.springidol.Instrument"/> </context:component-scan>
- type的5中类型
1.annotation:扫面指定注解所标注的类,通过expression指定注解。
2.assignable:扫面派生于expression指定类型的哪些类。
3.aspectj:扫面与expression指定的aspectJ表达式匹配的类
4.custom:指定expression使用的自定义TypeFilter实现类。
5.regex:正则匹配的类。
- type的5中类型
-
除了使用<context:include-filter>来告知<onctext:component-scan>哪些类需要注册为Spring Bean以外,还可以使用
<context:exclude-filter>
告知<onctext:component-scan>哪些类不需要注册为Spring Bean。
-
-
Spring基于Java的配置
让我们使用极少量的XML语言
而是用Java语言
实现配置。
-
启用Java配置
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd http:..www.springframework.org/schema/context http:..www.springframework.org/schema/context/spring-context.xsd"> // <context:component-scan>会自动加载使用@Configuration注解所标注的类。 <context:component-scan base-package="com.roger.spring.beans"> </context:component-scan> </beans>
-
定义一个配置类
在基于java的配置里使用@Configuration
注解java类,等价于xml配置中的<beans>元素。它告知Spring:这个类将包含一个或多个Spring Bean的定义,这些Bean的定义时使用@Bean
注解所标注的方法import org.springframework.context.annotation.Configuration; @Configuration public class SpringConfig { //@Bean告知Spring这个方法将返回一个对象,该对象应该被注册为Spring应用上下文中的一个Bean,方法名作为Bean的id。 @Bean public Person roger() { return new Teacher(); } }
-
使用Spring基于java的配置进行注入
//简单值注入 @Bean public A get(){ return new B(12); } @Bean public A get(){ B b = new B(); b.setName("jack"); return B; } //引用注入 //注意:通过@Bean注解标注address()方法,要在其他Bean的声明方法中引用这个方法时, //Spring都会拦截方法的调用,并尝试在应用上下文中查找该Bean,而不是让方法创建一个新的实例。 @Bean public A get(){ return new B(); } @Bean public C set(){ return new C(get()); }
Spring JDBS框架
Spring 事物管理
#参考文献
https://www.zhihu.com/question/21142149 —什么是Spring
https://www.ibm.com/developerworks/cn/java/wa-spring1/index.html —Spring
http://wiki.jikexueyuan.com/project/spring/ —Spring
https://blog.csdn.net/qq_35246620/article/details/54704656 —Spring MVC
https://blog.csdn.net/LPlanguage/article/details/70598501 —Spring MVC
https://blog.csdn.net/qq_19865749/article/details/70155529 —Spring容器
https://blog.csdn.net/chenssy/article/details/8188570 —Spring容器
https://blog.csdn.net/lutianfeiml/article/details/51731219 —Spring入门第1天–IOC快速入门
https://blog.csdn.net/u012049463/article/details/11807587 —Spring配置文件
https://my.oschina.net/itblog/blog/203436 Spring容器中Bean的作用域
https://www.cnblogs.com/xing901022/p/4248674.html 内部Bean
https://www.cnblogs.com/huang0925/p/3624526.html 使用p-namesapce和c-namespace简化bean的定义
https://blog.csdn.net/sunnyyoona/article/details/50638957 SpEL表达式
https://blog.csdn.net/u014034934/article/details/60579887 自动装配
https://my.oschina.net/u/1020238/blog/502930 自动装配
https://blog.csdn.net/yuanye348623610/article/details/8823429 AOP术语
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)