一、概述
1、什么样的对象放入容器中
dao、service、controller、工具类等(<bean>
、注释)
spring中的对象默认都是单例,在容器中叫这个名称的对象只有一个
2、不放入到spring容器中的对象
实体类对象,来自数据库;
servlet、listener、filter
二、IOC控制反转
IOC实现解耦合,如Service和dao等业务对象之间的解耦合
依赖注入:DI(Dependency Injection)
1、创建对象
<bean id=" 唯一名称 " class="实现类的全限定名"/>
<bean />
:定义一个实例对象。一个实例对应一个 bean 元素。
id:该属性是 Bean 实例的唯一标识,程序通过 id 属性访问 Bean, Bean 与 Bean 间的依赖关系也是通过 id 属性关联的。
class:指定该 Bean 所属的类,注意这里只能是类,不能是接口。
config = "beans.xml";
ApplicationContext ac = new ClassPathXmlApplicationContext(config);
Serives serives = (Serives)ac.getBean("someSerives");
2、基于xml的注入
修改少时用注释注入,修改多时用set注入
set注入
spring调用类的set方法实现对属性赋值
简单类型:
<property name="属性名" value="属性的值" />
引用类型:
<property name="属性名" ref="beande id" />
构造注入
spring调用有参数的构造方法
<constructor-arg>
的name属性,name表示构造方法的形参名
自动注入
给引用类型赋值
byName
byType
3、注释注入
@Component,创建对象
@Repository,创建dao对象,访问数据库
@Service,创建Service对象,处理业务逻辑,有事务功能
@Controller,创建控制器对象,接收请求,显示处理结果
@Value,简单类型的属性赋值
@Autowried,spring中引用类型的赋值,默认byType,byName:加上@Qualifier("id")
@Resource,jdk中的注释,自动注入引用类型赋值,默认byName,byType,会自动检索是否符合这两种类型,也可无需设置。
使用步骤
1、加入依赖:spring-context,间接加入spring-aop
2、在类中加入注释
3、在spring配置文件中,加入组件扫描器的标签:
<context:component-scan base-package="包名" />
三、AOP面向切面编程
1、概述
AOP是动态代理的规范化
底层是动态代理:jdk动态代理(目标类必须实现接口)、cglib动态代理(继承)
2、作用:
增强功能:在不修改原来功能代码上,增加其他切面功能(日志、事务、统计信息、参数检查、权限验证等);
解耦合:让业务功能与非业务功能分离
3、三个要素
1、切面代码的功能
2、切面代码的执行位置:Pointcut
3、切面代码的执行时间:Advice
4、Aspectj框架
1)执行时间,Advice(通知、增强)
@Before:JoinPoint,获取目标方法的信息,以下通知都包含这个参数
@AfterReturning:returning,可用来修改目标方法的返回值
@Around:最强通知、ProceedingjoinPoint、ProceedingjoinPoint.proceed(),
@AfterThrowing:throwing,用来记录目标方法抛出的异常
@After:无论是否抛出异常,均会被执行(类似finally)
@Pointcut:简化execution
5、步骤
编写目标对象的接口和类
编写切面功能类
在spring文件中创建目标对象和切面对象、声明动态代理生成器
从spring容器中获取目标对象,并执行目标方法(该方法已经过修改)
2)执行位置,切入点表达式
execution(访问权限 *方法返回值* *方法声明(参数)* 异常类型)
execution(* *..service.*.*(..))
四、spring和mybatis整合
mybatis.xml
spring.xml
五、sping事务
1、事务常量
事务隔离级别:
- READ_UNCOMMITTED:读未提交。未解决任何并发问题。
- READ_COMMITTED:读已提交。解决脏读,存在不可重复读与幻读。 (Oracle默认级别)
- REPEATABLE_READ:可重复读。解决脏读、不可重复读,存在幻读。(JDBC默认级别)
- SERIALIZABLE: 串行化。不存在并发问题。
事务传播行为:
- PROPAGATION_REQUIRED
- PROPAGATION_REQUIRES_NEW
- PROPAGATION_SUPPORTS
- PROPAGATION_MANDATORY
- PROPAGATION_NESTED
- PROPAGATION_NEVER
- PROPAGATION_NOT_SUPPORTED
事务超时时限: TIMEOUT_DEFAULT
2、spring事务注释
配置spring
<!--声明事务管理器-->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="myDataSource"/>
</bean>
<!--声明事务注解驱动-->
<tx:annotation-driven transaction-manager="transactionManager"/>
@Transactional(propagation = Propagation.REQUIRED,
rollbackFor = {NotEnoughException.class,NullPointException.class})
public void buy(){}
3、aspect的aop配置事务
加入aspect依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
配置spring
<!--声明式事务处理:和源代码完全分离的-->
<!--1.声明事务管理器对象-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="myDataSource" />
</bean>
<!--2.声明业务方法它的事务属性(隔离级别,传播行为,超时时间)
id:自定义名称,表示 <tx:advice> 和 </tx:advice>之间的配置内容的
transaction-manager:事务管理器对象的id
-->
<tx:advice id="myAdvice" transaction-manager="transactionManager">
<!--tx:attributes:配置事务属性-->
<tx:attributes>
<!--tx:method:给具体的方法配置事务属性,method可以有多个,分别给不同的方法设置事务属性
name:方法名称,1)完整的方法名称,不带有包和类。
2)方法可以使用通配符,* 表示任意字符
propagation:传播行为,枚举值
isolation:隔离级别
rollback-for:你指定的异常类名,全限定类名。 发生异常一定回滚
-->
<tx:method name="buy" propagation="REQUIRED" isolation="DEFAULT"
rollback-for="java.lang.NullPointerException,com.bjpowernode.excep.NotEnoughException"/>
<!--使用通配符,指定很多的方法-->
<tx:method name="add*" propagation="REQUIRES_NEW" />
<!--指定修改方法-->
<tx:method name="modify*" />
<!--删除方法-->
<tx:method name="remove*" />
<!--查询方法,query,search,find-->
<tx:method name="*" propagation="SUPPORTS" read-only="true" />
</tx:attributes>
</tx:advice>
<!--配置aop-->
<aop:config>
<!--配置切入点表达式:指定哪些包中类,要使用事务
id:切入点表达式的名称,唯一值
expression:切入点表达式,指定哪些类要使用事务,aspectj会创建代理对象
com.bjpowernode.service
com.crm.service
com.service
-->
<aop:pointcut id="servicePt" expression="execution(* *..service..*.*(..))"/>
<!--配置增强器:关联adivce和pointcut
advice-ref:通知,上面tx:advice哪里的配置
pointcut-ref:切入点表达式的id
-->
<aop:advisor advice-ref="myAdvice" pointcut-ref="servicePt" />
</aop:config>
六、spring与web
1、添加依赖
pom.xml
<!-- servlet依赖 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- jsp依赖 -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.2.1-b03</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
2、配置监听器,让容器对象只创建一次,配置spring文件位置
web.xml
<!--注册监听器ContextLoaderListener
监听器被创建对象后,会读取/WEB-INF/spring.xml
为什么要读取文件:因为在监听器中要创建ApplicationContext对象,需要加载配置文件。
/WEB-INF/applicationContext.xml就是监听器默认读取的spring配置文件路径
可以修改默认的文件位置,使用context-param重新指定文件的位置
配置监听器:目的是创建容器对象,创建了容器对象, 就能把spring.xml配置文件中的所有对象都创建好。
用户发起请求就可以直接使用对象了。
-->
<context-param>
<!-- contextConfigLocation:表示配置文件的路径 -->
<param-name>contextConfigLocation</param-name>
<!--自定义配置文件的路径-->
<param-value>classpath:spring.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
3、获取spring对象
通过监听器来获取对象,代替spring容器获取对象,使得在整个业务过程中,值创建一次对象,节省资源。
servletContext sc = getServletContext();
WebApplicationContext ctx = null;
ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(sc);
StudentService service = (StudentService) ctx.getBean("myStudentService");