文章目录
IOC
IoC也称为依赖注入(DI)。在此过程中,对象仅通过构造函数参数、工厂方法参数或在对象实例被构造或从工厂方法返回后设置的属性来定义它们的依赖项(即它们使用的其他对象)。然后容器在创建bean时注入这些依赖项。从根本上说,这个过程是bean本身通过直接构造类来控制依赖项的实例化或位置的相反过程(因此得名“控制倒置”)
IOC的Maven依赖坐标
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.3.6</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.6</version>
</dependency>
IOC容器
applicationcontext
接口表示Spring IoC容器,负责实例化、配置和组装bean。容器通过读取配置元数据获得关于实例化、配置和组装哪些对象的指令。配置元数据用XML、Java注释或Java代码表示,以下是它的重要实现。
实现 | 说明 |
---|---|
ClassPathXmlApplicationContext | 它可以加载类路径下的配置文件 |
FileSystemXmlApplicationContext | 它可以加载磁盘任意路径下的配置文件,权限不够的加载不了 |
AnnotationConfigApplicationContext | 加载注解配置类 |
在Spring中,由IOC容器管理的构成应用程序主干的对象称为bean。bean是由IOC容器实例化、组装和管理的对象。IOC容器管理一个或多个bean。这些bean通过配置文件中的配置元数据创建。在容器本身内,这些bean定义表示为BeanDefinition
对象,其中包含以下配置信息:
配置信息 | 说明 |
---|---|
Class | |
Name | |
Scope | |
Constructor arguments | |
Properties | |
Autowiring mode | |
Lazy initialization mode | |
Initialization method | |
Destruction method |
id和name
id和name属性用于指定bean的标识符,唯一的区别在于name可以指定多个标识符,而id只能指定一个。
class
使用构造函数进行实例化
在容器本身通过反射调用构造函数直接创建bean的情况下,指定要构造的bean类,这在某种程度上相当于带有new操作符的Java代码。
<bean id="exampleBean" class="examples.ExampleBean"/>
<bean name="anotherExample" class="examples.ExampleBeanTwo"/>
使用静态工厂方法进行实例化
在定义使用静态工厂方法创建的bean时,使用class属性指定包含静态工厂方法的类,并使用名为factory-method的属性指定工厂方法本身的名称。
<bean id="clientService"
class="examples.ClientService"
factory-method="createInstance"/>
使用实例工厂方法进行实例化
在使用实例工厂方法进行实例化时,将class属性保留为空,并在factory-bean属性中,指定当前容器中bean的名称,该bean包含要被调用来创建对象的实例方法。使用factory-method属性设置工厂方法本身的名称。
<bean id="serviceLocator" class="examples.DefaultServiceLocator">
</bean>
<bean id="clientService"
factory-bean="serviceLocator"
factory-method="createClientServiceInstance"/>
scope
Bean的作用范围有两层含义:第一是这个bean会被实例化几次。第二是bean存活的时间。bean 标签里面的scope属性用于设置bean的作用域。
范围 | 说明 |
---|---|
singleton | (默认)一个bean对应每个IOC容器中的一个对象 |
prototype | 一个bean对应每个IOC容器中的多个对象 |
request | 一个bean对应每个request生命周期中的一个对象 |
session | 一个bean对应每个session生命周期中的一个对象 |
application | 一个bean对应每个ServletContext生命周期中的一个对象 |
websocket | 一个bean对应每个websocket生命周期中的一个对象 |
Bean生命周期
Bean的生命周期是指从Bean对象创建到销毁的过程
- 实例化
- 依赖注入
- 初始化方法
- 使用
- 销毁方法
其中初始化方法和销毁方法要使用 init-method和destory指定
Lazy initialization mode
默认情况下IOC容器会在启动时实例化所有bean,但是可以使用懒加载模式禁止这一行为,让bean在使用时才实例化。
<bean id="lazy" class="com.something.ExpensiveToCreateBean" lazy-init="true"/>
<bean name="not.lazy" class="com.something.AnotherBean"/>
<!--所有bean都懒加载-->
<beans default-lazy-init="true">
<!-- no beans will be pre-instantiated... -->
</beans>
Initialization method
<bean id="exampleInitBean" class="examples.ExampleBean" init-method="init"/>
Destruction method
<bean id="exampleInitBean" class="examples.ExampleBean" destroy-method="cleanup"/>
依赖注入
依赖注入是一个过程,对象通过构造函数参数、工厂方法的参数或在对象实例被构造或从工厂方法返回后设置的属性来定义它们的依赖项。然后,容器在创建bean时注入这些依赖项。
注入方式
构造函数注入
基于构造函数的依赖注入是通过容器调用带有许多参数的构造函数来完成的,每个参数表示一个依赖项。如果bean定义的构造函数参数中不存在潜在的歧义,那么在<bean>中<constructor-arg>的顺序就是在实例化bean时将这些参数提供给适当的构造函数的顺序。大部分情况都应该使用基于构造函数的依赖注入。
<beans>
<bean id="beanOne" class="x.y.ThingOne">
<constructor-arg ref="beanTwo"/>
<constructor-arg ref="beanThree"/>
</bean>
<bean id="beanTwo" class="x.y.ThingTwo"/>
<bean id="beanThree" class="x.y.ThingThree"/>
</beans>
type
当参数为简单类型时,Spring不能确定值的类型,此时就需要使用type指定类型。
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg type="int" value="7500000"/>
<constructor-arg type="java.lang.String" value="42"/>
</bean>
index
可以使用index属性显式地指定构造函数参数的顺序。常用于解决多个简单值的歧义以及构造函数具有两个相同类型参数的歧义。
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg index="0" value="7500000"/>
<constructor-arg index="1" value="42"/>
</bean>
name
可以使用name属性显示指定构造函数参数名。
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg name="years" value="7500000"/>
<constructor-arg name="ultimateAnswer" value="42"/>
</bean>
setter注入
基于setter的依赖注入是通过容器在调用无参数构造函数或无参数静态工厂方法来实例化bean之后调用bean上的setter方法来完成的。基于setter的注入应该只用于可选依赖项,这些依赖项可以在类中分配合理的默认值。
<bean id="exampleBean" class="examples.ExampleBean">
<property name="beanOne">
<ref bean="anotherExampleBean"/>
</property>
<property name="beanTwo" ref="yetAnotherBean"/>
<property name="integerProperty" value="1"/>
</bean>
<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
方法注入
方法注入用于解决实例化次数不同bean之间的依赖问题。比如一个singleton
依赖一个prototype
,这会导致后者只会被注入一次。
public abstract class Person {
public Teacher teacher;
public Teacher getTeacher() {
return createTeacher();
}
public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}
protected abstract Teacher createTeacher();
}
public class Teacher {
public String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
<bean id="teacher" class="cn.superstallion.pojo.Teacher" scope="prototype"></bean>
<bean id="person" class="cn.superstallion.pojo.Person">
<lookup-method name="createTeacher" bean="teacher"></lookup-method>
</bean>
代理注入
代理注入用于解决存活时间不同bean之间的依赖问题。比如一个singleton
依赖一个request
,后者在每次请求都会被创建一次,但是只会被注入一次。
<bean id="userPreferences" class="com.something.UserPreferences" scope="request">
<aop:scoped-proxy/>
</bean>
<bean id="userManager" class="com.something.UserManager">
<property name="userPreferences" ref="userPreferences"/>
</bean>
注入类型
字面量
<constructor-arg name="years" value="7500000"/>
<property name="integerProperty" value="1"/>
bean
<constructor-arg name="beanTwo" ref="yetAnotherBean"/>
<property name="beanTwo" ref="yetAnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
内部bean
<bean id="outer" class="...">
<property name="target">
<bean class="com.example.Person">
<property name="name" value="Fiona Apple"/>
<property name="age" value="25"/>
</bean>
</property>
</bean>
自动装配
Spring容器可以自动装配协作bean之间的关系。自动装配有以下几种模式。
<bean id="yetAnotherBean" class="examples.YetAnotherBean" autowire="autowireMode"/>
模式 | 说明 |
---|---|
no | (默认)没有自动装配。Bean引用必须由ref元素定义。 |
byName | 通过属性名自动装配。 |
byType | 如果容器中恰好有一个属性类型的bean,则允许自动连接属性。如果存在多个,则抛出致命异常,这表明您不能对该bean使用byType自动装配。如果没有匹配的bean,则不会发生任何事情(没有设置属性)。 |
constructor | 类似于byType,但应用于构造函数参数。如果容器中没有一个构造函数参数类型的bean,则会引发致命错误。 |
depends-on
在bena之间的依赖关系不是特别明显时可以使用depends-on
。
<bean id="beanOne" class="ExampleBean" depends-on="manager,accountDao">
<property name="manager" ref="manager" />
</bean>
<bean id="manager" class="ManagerBean" />
<bean id="accountDao" class="x.y.jdbc.JdbcAccountDao" />
级联属性注入
<bean id="something" class="things.ThingOne">
<property name="fred.bob.sammy" value="123" />
</bean>
集合注入
数组注入
<array>
<value>aaa</value>
<ref bean=""></ref>
</array>
list注入
<list>
<value>qqq</value>
<ref bean=""></ref>
</list>
map注入
<map>
<entry key="1" value="hh"></entry>
<entry key="2">
<value>www</value>
</entry>
</map>
set注入
<set>
<value>haha</value>
<ref bean=""></ref>
</set>
property注入
<props>
<prop key="key">value</prop>
</props>
集合合并
子集合可以继承或覆盖父集合中的内容。
<beans>
<bean id="parent" abstract="true" class="example.ComplexObject">
<property name="adminEmails">
<props>
<prop key="administrator">administrator@example.com</prop>
<prop key="support">support@example.com</prop>
</props>
</property>
</bean>
<bean id="child" parent="parent">
<property name="adminEmails">
<!-- the merge is specified on the child collection definition -->
<props merge="true">
<prop key="sales">sales@example.com</prop>
<prop key="support">support@example.co.uk</prop>
</props>
</property>
</bean>
<beans>
null和空字符串
空字符串
<bean class="ExampleBean">
<property name="email" value=""/>
</bean>
null
<bean class="ExampleBean">
<property name="email">
<null/>
</property>
</bean>
外部文件注入
引入外部文件
<context:property-placeholder location="jdbc.properties"></context:property-placeholder>
使用springEL表达式过去文件中的值
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
</bean>
AOP
面向切面编程,简单的说它就是把我们程序重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,在不修改源码的基础上,对我们的已有方法进行增强。在spring中可以基于AspectJ注解或基于Spring XML配置的AOP。
AOP的Maven依赖坐标
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.9.RELEASE</version>
</dependency>
AOP的相关术语
术语 | 说明 |
---|---|
Joinpoint(连接点) | 能够被增强的方法 |
Pointcut(切入点) | 实际被增强的方法 |
Advice(通知) | 通知是指实际增强的具体内容。通知的类型:前置通知,后置通知,异常通知,最终通知,环绕通知。 |
Aspect(切面) | 存放通知的类 |
Target(目标对象) | 代理的目标对象。 |
Proxy(代理) | 一个类被 AOP 织入增强后,就产生一个结果代理类。 |
切入点表达式
切入点表达式的作用是指定切入点,也就是指定对哪些方法进行增强。
execution(访问修饰符 返回值 全限定类名.方法名(参数类型))
访问修饰符 | 可以省略 |
返回值 | 可以使用*号,表示任意返回值 |
全限定类名 | 可以使用*号,表示任意类 |
方法名 | 可以使用*号,表示任意方法 |
参数列表 | 1、可以直接写数据类型 2、可以使用*,表示参数可以是任意数据类型 3、可以使用…表示有无参数均可,有参数可以是任意类型 |
注解
注解 | 属性 | 属性值 | 说明 |
---|---|---|---|
@Aspect | value | / | 把当前类声明为切面类 |
@Before | value argNames |
value:切入点表达式 | 把当前方法看成是前置通知 |
@After | 同上 | 同上 | 把当前方法看成是最终通知。 |
@AfterReturning | value argNames returning |
value:同上 argNames:同上 returning:指定方法参数列表中的返回值变量名 |
把当前方法看成是返回通知。 |
@AfterThrowing | value argNames throwing |
value:同上 argNames:同上 throwing:指定参数列表中的异常变量名 |
把当前方法看成是异常通知。 |
@Around | 同上 | 同上 | 把当前方法看成是环绕通知。 |
@Pointcut | value | 切入点表达式 | 配置公共切入点 |
@Order | value | 一个正整数,默认值为int的最大值 | 用于指定切面的优先级,值越小优先级越高 |
spring事务管理
spring事务管理是springAOP最重要的实现功能。
@Transactional
@Target({ElementType.TYPE, ElementType.METHOD})
属性 | 属性值 | 说明 |
---|---|---|
propagation | Propagation.REQUIRED:使用调用者的事务,默认属性值 Propagation.REQUIRES_NEW:使用被调用者的事务 |
控制事务的传播 |
isolation | Isolation.DEFAULT:与数据库的默认提交方式相同 Isolation.READ_UNCOMMITTED:读未提交 Isolation.READ_COMMITTED读已提交 Isolation.REPEATABLE_READ:可重复读 Isolation.SERIALIZABLE串行化 |
设置事务的隔离级别 |
timeout | int型秒数 | 设置在事务强制回滚前可以等待的时间 |
readOnly | 默认为false | 指定当前事务中所有的操作是否为只读,若设置为只读mysql就会在数据访问的时候不加锁提高性能 |
rollbackFor | 异常字节码文件 | 设置当发生什么异常时事务回滚 |
rollbackForClassName | 异常全限定类名 | 同上 |
noRollbackFor | 异常字节码文件 | 设置当发生什么异常时事务不应该回滚 |
noRollbackForClassName | 异常全限定类名 | 同上 |
完全注解开发
@Configuration
使用此注解的类为配置类,表示该类的主要目的是作为 Bean 定义的来源。
@Target({ElementType.TYPE})
@ComponentScan
此注解用于自动检测构造型类,并向ApplicationContext注册相应的BeanDefinition实例。
@Target({ElementType.TYPE})
String[] value() default {};//基础包
String[] basePackages() default {};//基础包
ComponentScan.Filter[] includeFilters() default {};//包含过滤器
ComponentScan.Filter[] excludeFilters() default {};//移除过滤器
@Filter
过滤器。
FilterType type() default FilterType.ANNOTATION;//过滤器类型
Class<?>[] value() default {};//指定过滤注解类
Class<?>[] classes() default {};//指定过滤注解类
String[] pattern() default {};//指定表达式
过滤器类型 | 说明 |
---|---|
annotation | 在目标组件的类型级别上存在的 注解。 |
assignable | 目标组件可分配给(扩展或实现)的类(或接口)。 |
aspectj | 目标组件要匹配的 AspectJ 类型表达式。 |
regex | 要与目标组件类名称匹配的正则表达式。 |
custom | org.springframework.core.type .TypeFilter接口的自定义实现。 |
@Bean
在带@Configuration注解的类中定义 Bean。
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
String[] value() default {};//bean标识符
String[] name() default {};//bean标识符
boolean autowireCandidate() default true;//支持自动装配
String initMethod() default "";//初始化方法
String destroyMethod() default "(inferred)";//销毁方法
@Scope
指定bean的范围。
@Target({ElementType.TYPE, ElementType.METHOD})
String value() default "";
String scopeName() default "";
@Import
导入其它配置类。
@Target({ElementType.TYPE})
Class<?>[] value();
@ImportResource
导入xml配置文件。
@Target({ElementType.TYPE})
String[] value() default {};
@PropertySource
导入键值对文件。
@Target({ElementType.TYPE})
String[] value();
@EnableAspectJAutoProxy
开启AspectJ注解支持。
@Target({ElementType.TYPE})
@EnableTransactionManagement
开启事务支持。
@Target({ElementType.TYPE})
用于注册bean的注解
注解 | 属性 | 说明 |
---|---|---|
@Component | value | 用于标识在实体类上 value用于设置id值,默认为被标注类的类名的首字母小写字符串 |
@Controller | 同上 | 用于标识在控制层上 |
@Service | 同上 | 用于标识在服务层上 |
@Repository | 同上 | 用于表示在持久层上 |
@Bean | name:用于指定bean的id,不写默认为当前方法的名称 | 把当前方法的返回值当作bean存入到IOC容器中 当使用注解配置方法时如果方法有参数,spring会容器中查找有没有可用的bean对象注入,查找的方式和@Autowired的作用是一样的. |
@PostContstruct
指定初始化方法。
@PreDestroy
指定bean销毁方法。
@Value
@Value用于注入字面量值,它可以使用EL表达式。
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
String value();//指定值
当value值为EL表达式时但没有数据与之匹配,此时就会将EL表达式作为字符串注入,可以添加一个配置类来解决这个问题:
@Configuration
public class AppConfig {
@Bean
public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
@Autowired
@Autowired注解按照依赖类型进行自动注入。
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
boolean required() default true;//是否必要
@Qualifier
在@Autowired的基础上按照名称进行注入。
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
String value() default "";//指定名称
@Resource
按照名称进行注入。
@Target({TYPE, FIELD, METHOD})
String name() default "";//指定名称