1.BeanFactory 和ApplicationContext 的区别
BeanFactory
才是Spring
容器中的顶层接口。
ApplicationContext
是它的子接口。
BeanFactory
和ApplicationContext
的区别:
创建对象的时间点不一样。
ApplicationContext
:只要一读取配置文件,默认情况下就会创建对象。
BeanFactory
:什么使用什么时候创建对象。
2.ApplicationContext 接口的实现类
ClassPathXmlApplicationContext
:
它是从类的根路径下加载配置文件 推荐使用这种
FileSystemXmlApplicationContext
:
它是从磁盘路径上加载配置文件,配置文件可以在磁盘的任意位置。
AnnotationConfigApplicationContext
:
当我们使用注解配置容器对象时,需要使用此类来创建spring 容器。它用来读取注解。
3.
<bean id="" class="" scope="" init-method="" destroy-method=""></bean>
(1) id:给对象在容器中提供一个唯一标识。用于获取对象。
(2) class:指定类的全限定类名。用于反射创建对象。默认情况下调用无参构造函数。
(3) scope:指定对象的作用范围。
singleton :默认值,单例的.
prototype :多例的.
request :WEB 项目中,Spring 创建一个Bean 的对象,将对象存入到request 域中.
session :WEB 项目中,Spring 创建一个Bean 的对象,将对象存入到session 域中.
global session :WEB 项目中,应用在Portlet 环境.如果没有Portlet 环境那么
globalSession 相当于session.
(4) init-method:指定类中的初始化方法名称。
(5) destroy-method:指定类中销毁方法名称。
实例化Bean 的三种方式
1.使用默认无参构造函数
<bean id="accountService" class="com.service.impl.AccountServiceImpl"/>`
它会根据默认无参构造函数来创建类对象。如果bean 中没有默认无参构造函数,将会创建失败。
2.spring 管理静态工厂-使用静态工厂的方法创建对象
public class StaticFactory {
public static IAccountService createAccountService(){
return new AccountServiceImpl();
}
}
<bean id="accountService" class="com.factory.StaticFactory" factory-method="createAccountService"></bean>
//factory-method 属性:指定生产对象的静态方法
3.spring 管理实例工厂-使用实例工厂的方法创建对象
public class InstanceFactory {
public IAccountService createAccountService(){
return new AccountServiceImpl();
}
}
<bean id="instancFactory" class="com.factory.InstanceFactory"></bean>
<bean id="accountService" factory-bean="instancFactory" factory-method="createAccountService"></bean>
//factory-bean 属性:用于指定实例工厂bean 的id。
//factory-method 属性:用于指定实例工厂中创建对象的方法。
spring 的依赖注入
1.构造函数注入
<bean id="now" class="java.util.Date"></bean>
<bean id="accountService" class="com.service.impl.AccountServiceImpl">
<constructor-arg name="name" value="张三"></constructor-arg>
<constructor-arg name="birthday" ref="now"></constructor-arg>
</bean>
<!--constructor-arg
属性:
index:指定参数在构造函数参数列表的索引位置
type:指定参数在构造函数中的数据类型
name:指定参数在构造函数中的名称 用这个找给谁赋值
===上面三个都是找给谁赋值,下面两个指的是赋什么值的===
value:它能赋的值是基本数据类型和String 类型
ref:它能赋的值是其他bean 类型,也就是说,必须得是在配置文件中配置过的bean
-->
2.set 方法注入
<bean id="now" class="java.util.Date"></bean>
<bean id="accountService" class="com.service.impl.AccountServiceImpl">
<property name="name" value="test"></property>
<property name="birthday" ref="now"></property>
</bean>
<!--property
属性:
name:找的是类中set 方法后面的部分
ref:给属性赋值是其他bean 类型的
value:给属性赋值是基本数据类型和 string 类型的-->
3.使用p 名称空间注入数据(本质还是调用set 方法)
xmlns:p="http://www.springframework.org/schema/p"
<bean id="accountService" class="com.service.impl.AccountServiceImpl"
p:name="test" p:age="21" p:birthday-ref="now"/>
</beans>
4.注入集合属性
List 结构的:array,list,set
<property name="mylist">
<list>
<value>AAA</value>
<value>BBB</value>
<value>CCC</value>
</list>
</property>
Map 结构的:map,entry,props,prop
<property name="myMap">
<map>
<entry key="testA" value="aaa"></entry>
<entry key="testB"> <value>bbb</value></entry>
</map>
</property>
注解配置
曾经XML的配置:
<bean id="" class="" scope="" init-method="" destroy-method="">
<property name="" value="" | ref=""></property>
</bean>
创建对象
作用和在XML
配置文件中编写一个相当于<bean>
标签实现的功能一样
Component
:
作用:用于把当前类对象存入spring
容器中
属性:
value
:用于指定bean
的id
。当我们不写时,它的默认值是当前类名,且首字母改小写。
Controller
:一般用在表现层
Service
:一般用在业务层
Repository
:一般用在持久层
以上三个注解他们的作用和属性与Component
是一模一样。
他们三个是spring框架为我们提供明确的三层使用的注解,使我们的三层对象更加清晰
注入数据
作用和在xml
配置文件中的bean标签中写一个<property>
标签的作用一样
Autowired:
作用:自动按照类型注入。只要容器中有唯一的一个bean对象类型和要注入的变量类型匹配,就可以注入成功
如果Ioc容器中没有任何bean的类型和要注入的变量类型匹配,则报错。
如果Ioc容器中有多个类型匹配时:
出现位置:
可以是变量上,也可以是方法上
细节:
在使用注解注入时,set方法就不是必须的了。
Qualifier:
作用:在自动按照类型注入的基础之上,再按照 Bean 的 id 注入。它在给字段注入时不能独立使用,必须和@Autowire 一起使用;
但是给方法参数注入时,可以独立使用
属性:
value:用于指定注入bean的id。
Resource
作用:直接按照bean的id注入。它可以独立使用
属性:
name:用于指定bean的id。
以上三个注入都只能注入其他bean类型的数据,而基本类型和String类型无法使用上述注解实现。
另外,集合类型的注入只能通过XML来实现。
Value
作用:用于注入基本类型和String类型的数据
属性:
value:用于指定数据的值。它可以使用spring中SpEL(也就是spring的el表达式)
SpEL的写法:${表达式}
用于改变作用范围的
他们的作用就和在bean标签中使用scope属性实现的功能是一样的
Scope
作用:用于指定bean的作用范围
属性:
value:指定范围的取值。常用取值:singleton prototype
生命周期相关
他们的作用就和在bean标签中使用init-method和destroy-methode的作用是一样的
PreDestroy
作用:用于指定销毁方法
PostConstruct
作用:用于指定初始化方法
新注解
Configuration
用于指定当前类是一个spring配置类,当创建容器时会从该类上加载注解。获取容器时需要使用AnnotationApplicationContext(有@Configuration注解的类.class)。
属性:value:用于指定配置类的字节码
ComponentScan
作用: 用于指定spring在初始化容器时要扫描的包。作用和在spring的xml配置文件中的:
属性:<context:component-scan base-package="com"/>是一样的。
Bean
作用: 该注解只能写在方法上,表明使用此方法创建一个对象,并且放入spring容器。
属性: name:给当前@Bean注解方法创建的对象指定一个名称(即bean的id)。
PropertySource
作用:用于加载.properties文件中的配置。例如我们配置数据源时,可以把连接数据库的信息写到properties配置文件中,就可以使用此注解指定properties配置文件的位置。
属性: value[]:用于指定properties文件位置。如果是在类路径下,需要写上classpath:
Import
作用: 用于导入其他配置类,在引入其他配置类时,可以不用再写@Configuration注解。当然,写上也没问题。
属性: value[]:用于指定其他配置类的字节码。
使用Junit单元测试
Spring整合junit的配置
1、导入spring整合junit的jar(坐标spring-test)
2、使用Junit提供的一个注解把原有的main方法替换了,替换成spring提供的
@Runwith(SpringJUnit4ClassRunner.class)
3、告知spring的运行器,spring和ioc创建是基于xml还是注解的,并且说明位置
@ContextConfiguration
locations:指定xml文件的位置,加上classpath关键字,表示在类路径下
classes:指定注解类所在地位置
当我们使用spring 5.x版本的时候,要求junit的jar必须是4.12及以上
AOP
作用: 在程序运行期间,不修改源码对已有方法进行增强。
优势: 减少重复代码 提高开发效率 维护方便
实现方式: 使用动态代理技术
动态代理常用的有两种方式
1.基于接口的动态代理
提供者:JDK官方的Proxy类。
要求:被代理类最少实现一个接口。
2.基于子类的动态代理
提供者:第三方的CGLib
,如果报asmxxxx
异常,需要导入asm.jar
。
要求:被代理类不能用final
修饰的类(最终类)。
Enhancer.create(actor.getClass(), new MethodInterceptor(){
@Override public Object intercept(
Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
})
AOP相关术语
Joinpoint
(连接点):
所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点。
Pointcut
(切入点):
所谓切入点是指我们要对哪些Joinpoint进行拦截的定义。
Advice
(通知/增强):
所谓通知是指拦截到Joinpoint之后所要做的事情就是通知。
通知的类型:前置通知,后置通知,异常通知,最终通知,环绕通知。
Introduction
(引介):
引介是一种特殊的通知在不修改类代码的前提下, Introduction可以在运行期为类动态地添加一些方法或Field。
Target
(目标对象):
代理的目标对象。
Weaving
(织入):
是指把增强应用到目标对象来创建新的代理对象的过程。
spring采用动态代理织入,而AspectJ采用编译期织入和类装载期织入。
Proxy
(代理):
一个类被AOP织入增强后,就产生一个结果代理类。
Aspect
(切面):
是切入点和通知(引介)的结合。
AOP通过XML配置
<!--配置AOP-->
<aop:config>
<!--配置切面 -->
<aop:aspect id="" ref="">
<!-- 配置通知的类型,并且建立通知方法和切入点方法的关联-->
<aop:before method="" pointcut="execution(* com.service.impl.*.*(..))"></aop:before>
</aop:aspect>
</aop:config>
使用aop:pointcut配置切入点表达式
aop:pointcut:
作用: 用于配置切入点表达式。
<aop:pointcut expression="execution( * *..*.*(..) )" id="pt"/>
切入点表达式说明
execution:匹配方法的执行(常用)
表达式语法:execution([修饰符] 返回值类型 包名.类名.方法名(参数))
全通配方式: * *..*.*(..)
全匹配方式: public void com.service.impl.AccountServiceImpl.saveAccount(com.domain.Account) 访问修饰符可以省略
配置对应的通知类型
aop:before -- 用于配置前置通知。指定增强的方法在切入点方法之前执行
method:用于指定通知类中的增强方法名称
ponitcut-ref:用于指定切入点的表达式的引用
poinitcut:用于指定切入点表达式
aop:after-returning -- 用于配置后置通知
aop:after-throwing -- 用于配置异常通知
aop:after -- 用于配置最终通知
aop:around -- 用于配置环绕通知,通常情况下,环绕通知都是独立使用的
AOP通过注解配置
-- @Aspect注解声明为切面
-- 注解配置通知
@Before("execution(* com.service.impl.*.*(..))")
-- 在spring配置文件中开启spring对注解AOP的支持
<aop:aspectj-autoproxy/>
-- 环绕通知注解配置
@Around("execution(* com.service.impl.*.*(..))")
-- 切入点表达式注解
@Pointcut("execution(* com.service.impl.*.*(..))")
private void pt() {}
引用方式:
@Around("pt()") 注意:千万别忘了写括号
-- spring开启注解AOP的支持
@EnableAspectJAutoProxy
实现aop事务管理
本次选用xml方式配置
<!-- 配置事务管理 -->
<aop:config>
<!-- 配置切面 public void com.service.impl.AccountServiceImpl.*()-->
<aop:pointcut id="pt1" expression="execution(* com.service.impl.*.*(..))" />
<!-- 对方法增强 LOGGER 日志增强 事务增强 -->
<aop:aspect id="txAdvice" ref="txManager" order="1">
<!-- 通知配置 前置通知是(开启事务) 后置通知 (提交事务) 异常通知(回滚事务) 最终通知(清除CONN) 环绕通知-->
<aop:before method="beginTransaction" pointcut-ref="pt1" />
<aop:after-returning method="commit" pointcut-ref="pt1" />
<aop:after-throwing method="rollback" pointcut-ref="pt1" />
<aop:after method="release" pointcut-ref="pt1" />
</aop:aspect>
</aop:config>
事务的传播行为
• 1. PROPAGATION_REQUIRED
: 如果存在一个事务,则支持当前事务。如果没有事务则开启(默认)
• 2.PROPAGATION_SUPPORTS
: 如果存在一个事务,支持当前事务。如果没有事务,则非事务的执行
• 3.PROPAGATION_MANDATORY
: 如果已经存在一个事务,支持当前事务。如果没有一个活动的事务,则抛出异常。
• 4.PROPAGATION_REQUIRES_NEW
: 总是开启一个新的事务。如果一个事务已经存在,则将这个存在的事务挂起。
• 5. PROPAGATION_NOT_SUPPORTED
: 总是非事务地执行,并挂起任何存在的事务。
• 6. PROPAGATION_NEVER
: 总是非事务地执行,如果存在一个活动事务,则抛出异常
• 7. PROPAGATION_NESTED
:如果一个活动的事务存在,则运行在一个嵌套的事务中. 如果没有活动事务,
声明式事务
1,配置事务管理器
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
2.配置事务通知
<!-- 配置事务的通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager"></tx:advice>
3.配置AOP
<aop:config>
<!-- 配置切入点表达式-->
<aop:pointcut id="pt1" expression="execution(* com.service.impl.*.*(..))"></aop:pointcut>
<!--建立切入点表达式和事务通知的对应关系 -->
<aop:advisor advice-ref="txAdvice" pointcut-ref="pt1"></aop:advisor>
</aop:config>
4.切入点链接事务管理器
<aop:advisor advice-ref="txAdvice" pointcut-ref="pt1"></aop:advisor>
5、配置事务的属性
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!-- 配置事务的属性
isolation:用于指定事务的隔离级别。默认值是DEFAULT,表示使用数据库的默认隔离级别。
*propagation:用于指定事务的传播行为。默认值是REQUIRED,表示一定会有事务,增删改的选择。查询方法可以选择SUPPORTS。
*read-only:用于指定事务是否只读。只有查询方法才能设置为true。默认值是false,表示读写。
timeout:用于指定事务的超时时间,默认值是-1,表示永不超时。如果指定了数值,以秒为单位。
rollback-for:用于指定一个异常,当产生该异常时,事务回滚,产生其他异常时,事务不回滚。没有默认值。表示任何异常都回滚。
no-rollback-for:用于指定一个异常,当产生该异常时,事务不回滚,产生其他异常时事务回滚。没有默认值。表示任何异常都回滚。
-->
<tx:attributes>
<tx:method name="*" propagation="REQUIRED" read-only="false"/>
<tx:method name="find*" propagation="SUPPORTS" read-only="true"></tx:method>
</tx:attributes>
</tx:advice>