一、使用spring框架的步骤
-
加入依赖
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.5.RELEASE</version> </dependency>
-
创建类:接口、实现类、没有接口的类
-
创建spring的配置文件,使用声明对象
-
创建使用容器中的对象,通过ApplicationContext接口和它的实现类ClassPathXmlApplicationContext的方法getBean()
二、基于注解的di
- 加入maven的依赖 spring-context,在你加入spring-context的同时,间接加入spring-aop的依赖。使用注解必须使用spring-aop依赖
- 在类中加入spring的注解(多个不同功能的注解)
- 在spring的配置文件中,加入一个组件扫描的标签,说明注解在你的项目中的位置。
三、注解
-
@Component:创建对象的,等同于的功能
。属性:value就是对象的名称,也就是bean的id值
value的值是唯一的,创建的对象在整个spring的容器中
。位置:在类的上面
@Component(value = “myStudent”)等同于
spring中和@component功能一致,创建对象的注解还有:
2.@Repository (用在持久层类的上面):放在dao的实现类上面,表示创建dao对象,dao对象是能访问数据库的。
3.@Service(用在业务层类的上面):放在service的实现类上面,创建service对象,service对象是做业务处理,可以有事务等功能的.
4.@Controller(用在控制器的上面)∶放在控制器(处理器)类的上面,创建控制器对象的,
控制器对象,能够接受用户提交的参数,显示请求的处理结果。
以上三个注解的使用语法和@component一样的。都能创建对象,但是这三个注解还有额外的功能。
@Repository , @Service , @controller是给项目的对象分层的。
四、指定多个包的扫描方式
第一种方式:使用多次组件扫描器,指定不同的包
<context:component-scan base-package="com.bjpowernode.bao1"/>
<context:comporant-scan base-package="com.bjpowernode.ba02"/>
第二种方式:使用分隔符(;或,)分隔多个包名
<context:component-scan base-package="com.bjpowernode.ba01;com.bjpowernode.bao2”/>
第三种方式:指定父包
<context:component-scan base-package="com.bjpowernode”/>
五、自动注入
/*引用类型
@Autowired:spring框架提供的注解,实现引用类型的赋值。
* spring中通过注解给引用类型赋值,使用的是自动注入原理,支持byName,byType
@Autowired:默认使用的是bytype自动注入。
属性:required,是一个boolean类型的,默认true
required=true :表示引用类型赋值失败,程序报错,并终止执行。
required=fals:引用类型如果赋值失败,程序正常执行,引用类型是null
*位置: 1)在属性定义的上面,无需set方法,推荐使用
2)在set方法的上面
*如果要使用byName方式,需要做的是:
* 1.在属性上面加入@Autowired
2.在属性上面加入@Qualifier(value="bean的id"):表示使用指定名称的bean完成赋值。
*/
/*如果要使用byName方式,需要做的是:
*1.在属性上面加入@Autowired
*2.在属性上面加入@Qualifier(value="bean的id"):表示使用指定名称的bean完成赋值。
*/
@Qualifier("myschool")
@Autowired
private school school;
public student() {
system.out.println("==student无参数构造方法===");
@Resource
/*引用类型
来自jdk中的注解,spring框架提供了对这个注解的功能支持,可以使用它给引用类
@Resource:
使用的也是自动注入原理,支持byName ,byType .默认是byName
位置:1.在属性定义的上面,无需set方法,推荐使用。
2.在set方法的上面
默认是byName:先使用byName自动注入,如果byName赋值失败,再使用byType
*/
六、aop
aop的实现
aop是一个规范,是动态的一个规范化,一个标准
aop的技术实现框架:
1.spring:spring在内部实现了aop规范,能做aop的工作。spring主要在事务处理时使用aop.我们项目开发中很少使用spring的aop实现。因为spring的aop比较笨重。
2.aspectJ:一个开源的专门做aop的框架。spring框架中集成了aspectj框架,通过spring就能使用aspectj的功能。
aspectJ框架实现aop有两种方式:
1.使更用xml的配置文件:配置全局事务
2.使用注解,我们在项目中要做aop功能,一般都使用注解,aspectj有5个注解。
七、AspectJ框架的使用
1、切面的执行时间,这个执行时间在规范中叫做Advice (通知,增强)
在aspectj框架中使用注解表示的。也可以使用xml配置文件中的标签
-
@Before
-
@AfterReturning
-
@Around
-
@AfterThrowing
-
@After
2、AspectJ 的切入点表达式
-
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern?name-pattern(parampattern)
throws-pattern?) -
execution(访问权限 方法返回值 方法声明(参数) 异常类型)
-
符号 意义 * 0至多个任意字符 … 用在方法参数中,表示任意多个参数用在包名后,表示当前包及其子包路径 + 用在类名后,表示当前类及其子类用在接口后,表示当前接口及其实现类 举例:
execution(public * (…))
指定切入点为:任意公共方法。
execution( set*(…))
指定切入点为:任何一个以“set”开始的方法。
execution(* com.xyz.service..(…))
指定切入点为:定义在 service 包里的任意类的任意方法。
execution(* com.xyz.service….(…))
指定切入点为:定义在 service 包或者子包里的任意类的任意方法。“…”出现在类名中时,后
面必须跟“”,表示包、子包下的所有类。
execution( …service..*(…))
指定所有包下的 serivce 子包下所有类(接口)中所有方法为切入点
3、使用aspectj实现aop的基本步骤:
1.新建maven项目
2.加入依赖
1 ) spring依赖
2 ) aspectj依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
3 ) junit单元测试
3.创建目标类:接口和他的实现类。要做的是给类中的方法增加功能
4.创建切面类:普通类
1)在类的上面加入@Aspect
2)在类中定义方法,方法就是切面要执行的功能代码
在方法的上面加入aspectj中的通知注解,例如@Before有需要指定切入点表达式execution()
5.创建spring的配置文件:声明对象,把对象交给容器统一管理 声明对象你可以使用注解或者xml配置文件
1)声明目标对象
2)声明切面类对象
3 )声明aspectj框架中的自动代理生成器标签。
自动代理生成器:用来完成代理对象的自动创建功能的。
4、AspectJ基于注解的AOP实现
1.1)定义业务接口与实现类----@Beforce前置通知
public interface SomeService{
void doSome(String name,int age)
}
public class SomeServiceImpl implemenets SomeService{
public void doSome(String name,int age){
System.out.println("执行了业务doSome方法")
}
}
2)定义切面类
类中定义了若干普通方法,将作为不同的通知方法,用来增强功能
@Aspecct
public class MyAspect{
/*
@Beforce:前置通知
属性:value 切入点表达式,表示切面执行的位置
位置:方法的定义上面
*/
@Beforce
public void myBeforce(){
//就是切面代码的功能,例如日志的输出,事务的处理
System.out.println("前置通知:在目标方法之前先执行,例如输出日志")
}
}
3)声明目标对象切面类对象
<!--声明目标类对象-->
<bean id="someServiceTarget" class="com.hxc.SomeServiceImpl"></bean>
<!--声明切面类对象-->
<bean id="myAspect" class="com.hxc.MyAspect"></bean>
4)注册Aspect的自动代理
<!--声明目标类对象-->
<bean id="someServiceTarget" class="com.hxc.SomeServiceImpl"></bean>
<!--声明切面类对象-->
<bean id="myAspect" class="com.hxc.MyAspect"></bean>
<!--声明自动代理生成器,创建代理-->
<aop:aspect-autoproxy/>
5)测试类中使用目标对象的id
public void test(){
String configLocation = "com/hxc/applicationContext.xml";
ApplicationContext ctx = new ClassPathXmlApplicationContext(configLocation);
//从spring容器中获取目标对象,目标就是经过aspect修改后的代理对象
SomeService proxy = (SomeService)ctx.getBean("someServiceTarget");
//通过代理执行业务方法,实现功能增强
proxy.doSome("zs",20);
}
2.1)@Around环绕通知
- 接口增加方法
public interface SomeService{
void doSome(String name,int age);
String doOther(String name,int age);
String doFirst(String name,int age);
}
- 接口方法的实现
@Override
public String doFirst(String name,int age){
System.out.println("执行了业务方法doFirst");
return "doFirst";
}
- 定义切面
@Around(value="execution(* *..SomeServiceImpl.doFirst(..))")
public Object myAroud(ProceedingJoinPoint pjp) throws Throwable{
Object obj = null;
//增强功能
System.out.println("环绕通知:在目标方法执行之前的,例如输出日志");
//执行目标方法的调用,等同于method.invoke(target,args)
obj = pjp.proceed();
//增强功能
System.out.println("环绕通知:在目标方法之后执行的,例如处理事务");
return obj;
}
3.1)@AfterReturning后置通知
- 接口增加方法
public interface SomeService{
void doSome(String name,int age);
String doOther(String name,int age)
}
- 实现方法
@Override
public String doOther(String name,int age){
System.out.println("执行了业务方法doOther");
return "abcd";
}
- 定义切面
@AfterReturning(value="execution(* *..SomeServiceImpl.doOther(..))",returning="result")
public void myAfterReturning(Object result){
//修改目标方法的执行结果
if(result != null){
String s = (String)result;
result = s.toUpperCase();
}
System.out.println("后置通知:在目标方法之后执行的功能增强,例如执行事务处理")
}
4.1)@Pointcut定义切入点
当较多的通知增强方法使用相同的 execution 切入点表达式时,编写、维护均较为麻烦。
AspectJ 提供了@Pointcut 注解,用于定义 execution 切入点表达式。
其用法是,将@Pointcut 注解在一个方法之上,以后所有的 execution 的 value 属性值均
可使用该方法名作为切入点。代表的就是@Pointcut 定义的切入点。这个使用@Pointcut 注解
的方法一般使用 private 的标识方法,即没有实际作用的方法。
@Afer(value="mypt()")
public void myAfter(){
System.out.println("最终通知:总是会被执行的方法")
}
/*
@Pointcut:用来定义和管理切面点。简化切入点的定义
*/
@Pointcut(value="* *..SomeServiceImpl.doThird(..)")
private void mypt(){
//无需代码
}
八、spring与mybatis整合
一、步骤:
1.新建maven项目
2.加人maven的依赖
1 ) spring依赖
2 ) mybatis依赖
3 ) mysql驱动
4 ) spring的事务的依赖
5 ) mybatis和spring集成的依赖: mybatis官方体用的,用来在spring项目中创建mybatis的sqlSesissonFactory , dao对象的
3.创建实体类
4.创建dao接口和mapper文件
5.创建mybatis主配置文件
6.创建service接口和实现类,属性是dao。
7.创建spring的配置文件:声明mybatis的对象交给spring创建
1)数据源
2 ) sqlsessionFactory
3 ) Dao对象
4)声明自定义的service
8.创建测试类,获取service对象,通过service调用dao完成数据库的访间
<!--单元测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!--spring核心IOC-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<!--做spring事务-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<!--mybatis依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.1</version>
</dependency>
<!--mybatis和spring集成的依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.1</version>
</dependency>
<!--mybatis驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.9</version>
</dependency>
<!--数据库连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.12</version>
</dependency>
<!--插件:-->
<build>
<resources>
<resource>
<directory>src/main/java</directory><!--所在的目录-->
<includes><!--包括目录下的.properties,.xml 文件都会扫描到-->
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
二、spring配置
<!--声明数据源DataSource ,作用是连接数据库-->
<bean id="myDataSource" class="com.alibaba.druid.pool.DruidDataSource"
init-method="init" destroy-method="close">
<!--set注入给DruidDataSource提供连接数据库信息-->
<property name="url" value="jdbc:mysql://localhost:3306/springdb"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
<property name="maxActive" value="20"/>
</bean>
<!--声明的是mybatis提供的SqlSessionFactoryBean类,这个类内部创建SqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--set注入 把数据库连接池付给datasource属性-->
<property name="dataSource" ref="myDataSource"/>
<!--mybatis主配置文件的位置
configLocation属性是Resource类型,读取配置文件
它的赋值,使用value,指定文件的路径,使用classpath:表示文件的位置
-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
</bean>
<!--创建dao对象,使用sqlSession的getMapper(StudentDao.class)
MapperScannerConfigurer:在内部调用getMapper()生成每个dao接口的代理对象
-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!--指定sqlSessionFactory对象的id-->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
<!--
指定包名,包名是dao接口所在的包名
MapperScannerConfigurer会扫描这个包中的所有接口,把每个接口都执行一次
getMapper()方法,得到每个接口的dao对象
创建好dao对象放入到spring的容器中
-->
<property name="basePackage" value="com.hxc.dao"/>
</bean>
九、事务
事务原本是数据库中的概念,在 Dao 层。但一般情况下,需要将事务提升到业务层,
即 Service 层。这样做是为了能够使用事务的特性来管理具体的业务。
在 Spring 中通常可以通过以下两种方式来实现对事务的管理:
(1)使用 Spring 的事务注解管理事务
(2)使用 AspectJ 的 AOP 配置管理事务
1、定义了五个事务隔离级别常量
这些常量均是以 ISOLATION_开头。即形如 ISOLATION_XXX。
➢ DEFAULT:采用 DB 默认的事务隔离级别。MySql 的默认为 REPEATABLE_READ; Oracle
默认为 READ_COMMITTED。
➢ READ_UNCOMMITTED:读未提交。未解决任何并发问题。
➢ READ_COMMITTED:读已提交。解决脏读,存在不可重复读与幻读。
➢ REPEATABLE_READ:可重复读。解决脏读、不可重复读,存在幻读
➢ SERIALIZABLE:串行化。不存在并发问题。
2、定义了七个事务传播行为
所谓事务传播行为是指,处于不同事务中的方法在相互调用时,执行期间事务的维护情
况。如,A 事务中的方法 doSome()调用 B 事务中的方法 doOther(),在调用执行期间事务的
维护情况,就称为事务传播行为。事务传播行为是加在方法上的。
事务传播行为常量都是以 PROPAGATION_ 开头,形如 PROPAGATION_XXX。
PROPAGATION_REQUIRED
PROPAGATION_REQUIRES_NEW
PROPAGATION_SUPPORTS
==============================以上三个需要掌握
PROPAGATION_MANDATORY
PROPAGATION_NESTEDPROPAGATION_NEVER
PROPAGATION_NOT_SUPPORTED
3、使用spring的事务注解管理事务
通过@Transactional 注解方式,可将事务织入到相应 public 方法中,实现事务管理。
- isolation:用于设置事务的隔离级别。默认值为isolation.DEFAULT
- readOnly:用于设置该方法对数据库的操作是否是只读的。默认值为false
- timeout:用于设置本操作与数据库连接的超时时限。单位为秒,类型为 int,默认值为
-1,即没有时限。 - rollbackFor:指定需要回滚的异常类。类型为 Class[],默认值为空数组。
- rollbackForClassName:指定需要回滚的异常类类名。类型为 String[],默认值为空数组。
- noRollbackFor:指定不需要回滚的异常类。类型为 Class[],默认值为空数组。
- noRollbackForClassName:指定不需要回滚的异常类类名。类型为 String[],默认值为空
数组。
需要注意的是,@Transactional 若用在方法上,只能用于 public 方法上。对于其他非 public
方法,如果加上了注解@Transactional,虽然 Spring 不会报错,但不会将指定事务织入到该
方法中。因为 Spring 会忽略掉所有非 public 方法上的@Transaction 注解。
若@Transaction 注解在类上,则表示该类上所有的方法均将在执行时织入事务。
具体实现步骤:
1)声明事务管理器
<!--声明事务管理器-->
<bean id="transactionManager">
<class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="datasource" ref="datasource"/>
</bean>
2)开启注解驱动
<!--声明事务注解驱动-->
<tx:annotation-driven transaction-manager="transactionManager"/>
transaction-manager:事务管理器 bean 的 id
3)业务层 public 方法加入事务属性
@Transactionl(propagation = Propagation.REQUIRED,rollbackFor={NotEnoughException.class,NullPointerException.class})
public void buy(Integer goodsId,Integer amount){
Sale sale = new Sale();
sale.setGid(goodsId);
sale.setNums(amount);
Goods goods = goodsDao.selectGoods(goodsId);
if(goods == null){
throw new NullPointerException("没有商品");
}
if (goods.getAmount()<amount){
throw new NotEnoughException("库存不足");
}
goods = new Goods();
goods.setAmount(amount);
goods.setId(goodsId);
goodsDao.updateGoods(goods);
}
4、使用AspectJ的AOP配置管理事务
1)加入 aspectj 的依赖坐标
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
2)在容器中添加事务管理器
<!--声明事务管理器-->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransationManager">
<property name="dataSource" ref="dataSource"/>
</bean>
3)配置事务通知
<!--事务通知-->
<tx:advice id="buyAdvice" 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.hxc.excep.NotEnoughException"/>
<tx:method name="add*" propagation="REQUIRED" isolation="DEFAULT"
rollback-for="java.lang.Exception"/>
<tx:method name="*" propagation="SUPPORTS"/>
</tx:attributes>
</tx:advice>
4)配置增强器
<!--aop配置:通知应用的切入点-->
<aop:config>
<aop:pointcut id="servicePt" expression="execution(* *..service..*.*(..))"/>
<aop:advisor advice-ref="buyAdvice" pointcut-ref="servicePt"/>
</aop:config>
十、使用 Spring 的器 监听器 ContextLoaderListener
对于 Web 应用来说,ServletContext 对象是唯一的,一个 Web 应用,只有一个
ServletContext 对象,该对象是在 Web 应用装载时初始化的。若将 Spring 容器的创建时机,
放在 ServletContext 初始化时,就可以保证 Spring 容器的创建只会执行一次,也就保证了
Spring 容器在整个应用中的唯一性。
当 Spring 容器创建好后,在整个应用的生命周期过程中,Spring 容器应该是随时可以被
访问的。即,Spring 容器应具有全局性。而放入 ServletContext 对象的属性,就具有应用的
全局性。所以,将创建好的 Spring 容器,以属性的形式放入到 ServletContext 的空间中,就
保证了 Spring 容器的全局性。
具体实现步骤:
1)注册监听器 ContextLoaderListener
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
Spring 为该监听器接口定义了一个实现类 ContextLoaderListener,完成了两个很重要的
工作:创建容器对象,并将容器对象放入到了 ServletContext 的空间中。
2)指定Spring配置文件的位置
ContextLoaderListener 在对 Spring 容器进行创建时,需要加载 Spring 配置文件。其默认
的 Spring 配置文件位置与名称为:WEB-INF/applicationContext.xml。但,一般会将该配置文
件放置于项目的 classpath 下,即 src 下,所以需要在 web.xml 中对 Spring 配置文件的位置及
名称进行指定。
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
3)获取spring容器对象
- 直接从ServletContext中获取
从对监听器 ContextLoaderListener 的源码分析可知,容器对象在 ServletContext 的中存
放的 key 为 WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE。所以,可
以直接通过 ServletContext 的 getAttribute()方法,按照指定的 key 将容器对象获取到。
//获取容器
String attr = WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE;
WebApplicationContext ac = (WebApplicationContext) this.getServletContext.getAttribute(arr);
- 通过WebApplicationContextUtils获取
工具类 WebApplicationContextUtils 有一个方法专门用于从 ServletContext 中获取 Spring
容器对象:getRequiredWebApplicationContext(ServletContext sc)
WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext())