Spring是Java EE编程领域的一个轻量级开源框架,该框架由一个叫Rod Johnson的程序员在 2002 年最早提出并随后创建,是为了解决企业级编程开发中的复杂性,实现敏捷开发的应用型框架 。 [2] Spring是一个开源容器框架,它集成各类型的工具,通过核心的Bean factory实现了底层的类的实例化和生命周期的管理。在整个框架中,各类型的功能被抽象成一个个的 Bean,这样就可以实现各种功能的管理,包括动态加载和切面编程。 [3] Spring是独特的,因为若干个原因:
它定位的领域是许多其他流行的framework没有的。Spring致力于提供一种方法管理你的业务对象。
Spring是全面的和模块化的。Spring有分层的体系结构,这意味着你能选择使用它孤立的任何部分,它的架构仍然是内在稳定的。例如,你可能选择仅仅使用Spring来简单化JDBC的使用,或用来管理所有的业务对象。
它的设计从底部帮助你编写易于测试的代码。Spring是用于测试驱动工程的理想的framework。
Spring对你的工程来说,它不需要一个以上的framework。Spring是潜在地一站式解决方案,定位于与典型应用相关的大部分基础结构。它也涉及到其他framework没有考虑到的内容。
方便解耦,简化开发:Spring通过容器,将对象的创建从代码中剥离出来,交给Spring控制,避免直接编码造成模块之间的耦合度高,用户也不必自己编码处理对象的单例和多例控制,主要关注接口功能即可,不用关注具体使用哪个实现类和实现细节问题。
AOP切面编程:AOP切面编程是程序设计的一种概念,Spring对该概念实现的比较好,通过切面编程我们可以在不修改原有代码的情况下实现功能的增加,通常用于 事务控制,日志记录,性能检测,权限控制等等。
声明式事务:事务的控制可以托管给Spring,我们通过注解或者配置文件声明事务的处理方式即可,不用我们自己去编码处理。
整合JUNIT,方便测试:spring整合JUNIT单元测试,对于项目的功能都可以进行轻松快速的测试,便于我们调试程序。
方便整合各种优秀的框架: SSM> Spring+SpringMVC +MyBatis 、SSH> Spring+Hibernate +Strust各种其他框架。
丰富的功能封装:spring对JAVAEE(JDBC ,JAVAMail,)都进行了一系列的封装,简化我们对于API的使用,提高程序的开发效率。
规范的源码学习样本:spring的源码设计巧妙,结构清晰,大量使用了设计模式,是java代码规范编写的典范,也是高级程序员面试中经常会问到的源码。
控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。
简单的说就是,创建对象的权利,或者是控制的位置,由JAVA代码转移到spring容器,由spring的容器控制对象的创建,就是控制反转,spring创建对象时,会读取配置文件中的信息,然后使用反射给我们创建好对象之后在容器中存储起来,当我们需要某个对象时,通过id获取对象即可,不需要我们自己去new.
一句话:创建对象交给容器
通过XML解析技术读取配置文件
<bean id="empDao" class="com.msb.dao.impl.EmpDaoImpl"></bean>
反射技术实例化对象,放到容器中
//获得类的字节码
Class clazz =Class.forName("com.msb.dao.impl.EmpDaoImpl")
//通过字节码实例化对象
Object obj = clazz.newInstance();
//对象放到一个map集合中
map.put("empDao",obj)
工厂模式返回 Bean 对象 getBean 方法
public Object getBean(String name){
Object obj =map.get(name);
return obj;
}
IOC接口
通过 set 赋值给对象赋值
<!--property 就是在使用set方法实现依赖注入-->
<bean id="user1" class="com.msb.bean.User">
<property name="userid" value="1"></property>
<property name="username" value="张三"></property>
<property name="password1" value="abcdefg"></property>
</bean>
通过有参构造给对象属性赋值
<!--
constructor-arg 就是在使用构造方法实现依赖注入
constructor-arg 的个数必须和某个构造方法的参数个数向对应
name指的是参数名
index指的是参数的索引
value指的是参数值
-->
<bean id="user2" class="com.msb.bean.User">
<constructor-arg name="userid" value="2"></constructor-arg>
<constructor-arg name="username" value="小明"></constructor-arg>
<constructor-arg name="password1" value="123456789"></constructor-arg>
</bean>
<bean id="user3" class="com.msb.bean.User">
<constructor-arg index="0" value="3"></constructor-arg>
<constructor-arg index="1" value="小黑"></constructor-arg>
<constructor-arg index="2" value="987654321"></constructor-arg>
</bean>
通过p名称空间和c名称空间给对象属性赋值
<?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:p="http://www.springframework.org/schema/p"
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">
配置对象:
<!--p名称空间,就是对property的简化处理-->
<bean id="user4" class="com.msb.bean.User" p:userid="4" p:username="小东" p:password2="111111" ></bean>
<!--c名称空间,就是对constructor-arg的简化-->
<bean id="user5" class="com.msb.bean.User" c:userid="5" c:username="小西" c:password1="222222" ></bean>
准备bean
package com.msb.bean;
/**
* @Author: bingwoo
*/
public class User {
private Integer userid;
private String username;
private String password1;
public void initUser(){
System.out.println("第三步:User初始化");
}
public User() {
System.out.println("第一步:User构造");
}
public void destoryUser(){
System.out.println("第五步:User销毁");
}
@Override
public String toString() {
return "User{" +
"userid=" + userid +
", username='" + username + '\'' +
", password1='" + password1 + '\'' +
'}';
}
public User(Integer userid, String username, String password1) {
this.userid = userid;
this.username = username;
this.password1 = password1;
}
public void setUserid(Integer userid) {
System.out.println("setUserid");
this.userid = userid;
}
public void setUsername(String username) {
System.out.println("第二步:User属性赋值");
this.username = username;
}
public void setPassword1(String password1) {
this.password1 = password1;
}
}
配置bean
<?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:p="http://www.springframework.org/schema/p"
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="user" class="com.msb.bean.User" init-method="initUser" destroy-method="destoryUser">
<property name="username" value="xiaoming"></property>
</bean>
</beans>
创建后置处理器 实现 BeanPostProcesser 重写两个方法
package com.msb.beanProcesser;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
/**
* @Author: bingwoo
*/
public class MyBeanProcesser implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
//Object bean 实例化的bean
//String beanName bean的id
System.out.println("bean:初始化方法之前");
return bean;// 这里必须return bean
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("bean:初始化方法之后");
return bean;// 这里必须returnbean
}
}
配置后置处理器,对容器中的所有bean添加后置处理器的生命周期
<?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:p="http://www.springframework.org/schema/p"
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="user" class="com.msb.bean.User" init-method="initUser" destroy-method="destoryUser">
<property name="username" value="xiaoming"></property>
</bean>
<bean id="myBeanProcesser" class="com.msb.beanProcesser.MyBeanProcesser"></bean>
</beans>
BeanPostProcessor接口作用
@Component 放在类上,用于标记,告诉spring当前类需要由容器实例化bean并放入容器中,该注解有三个子注解:
当不确定是哪一层,就用Component
这几个注解互相混用其实也可以,但是不推荐
第一步:在applicationContext.xml中配置开启注解扫描
<?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:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
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
">
<!--添加注解扫描,扫描指定的包,将包中的所有有注解的类实例化
base-package 后面放要扫描的包
如果有多个包需要扫描,可以使用逗号隔开 com.msb.bean,com.msb.service
或者可以写上一层包路径 com.msb
可以通过注解指定bean的id@Component("user1")
如果不指定,则id默认是 类名首字母小写
-->
<context:component-scan base-package="com.msb.bean"></context:component-scan>
</beans>
第二步:在类上添加注解,让spring容器给我们创建bean实例并存储于容器中
package com.msb.bean;
import org.springframework.stereotype.Component;
/**
* @Author: Ma HaiYang
* @Description: MircoMessage:Mark_7001
*/
@Component(value = "user1")
public class User {
}
组件扫描配置注解识别
<!--
use-default-filters="false"
默认值为true 代表使用默认的扫描过滤器
默认的扫描过滤器会识别并包含 @Component @Controller @Service @Repository 四个注解
不使用默认的filter,使用我们自己的filter
-->
<!--控制只扫描Controller注解-->
<context:component-scan base-package="com.msb" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!--控制不扫描Controller注解-->
<context:component-scan base-package="com.msb" use-default-filters="true">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
package com.msb.service.impl;
import com.msb.dao.UserDao;
import com.msb.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* @Author: bignwoo
*/
@Service
public class UserServiceImpl implements UserService {
/*
*@Autowired
* 根据类型到容器中去寻找对应的对象,找到后给当前属性赋值
* 不需要依赖 set方法
* 属性类型可以是接口,会自动匹配对应的实现类对象
* @Autowired配合 @Qualifier,可以通过名称指定注入的对象
*
* @Resource 如果不配置name 那么就是根据类型注入
* @Resource(name="userDaoImplB") 配置name,就是根据名称注入
*
*
* @Resource 是JDK中javax包的注解
* @Autowired 和 @Qualifier 是spring中的注解
*
* @Value 可以个普通属性赋值
* @Value 可以使用${}这种表达式获取系统的变量值
* 或者是.properties属性配置文件中的值
*
* */
//@Autowired
//@Qualifier("userDaoImplA")
//@Qualifier("userDaoImplB")
//private UserDao userDao ;
@Resource(name="userDaoImplB")
private UserDao userDao ;
@Value("${username}")
private String sname;
@Value("boy")
private String sgender;
@Value("${age}")
private Integer sage;
@Override
public void add() {
System.out.println("userServiceImpl add ... ... ");
System.out.println(sname);
System.out.println(sgender);
System.out.println(sage);
userDao.add();
}
}
静态代理中代理类与被代理类都需要实现同一个接口,这就说明我们的一个静态代理类只能代理一个类,并且还要事先知道我们要代理哪个类才能写代理类,如果我们有其他类还想使用代理那就必须再写一个代理类。然而在实际开发中我们是可能是有非常多的类是需要被代理的,并且事先我们可能并不知道我们要代理哪个类。所以如果继续使用静态代理反而会增加许多的工作量,并且效率低下,代码复用率也不好。
package com.msb.test;
/**
* @Author: bingwoo
*/
public class Test1 {
public static void main(String[] args) {
Person person =new Person("张三");
Court court=new Lawyer(person);
court.doCourt();
}
}
// 接口
interface Court{
void doCourt();
}
// 代理类
class Lawyer implements Court{
private Person person;
public Lawyer(Person person) {
this.person = person;
}
@Override
public void doCourt() {
System.out.println("律师取证:视频证明张三当时正在旅游,不在案发现场");
System.out.println("律师总结:张三不可能去杀人");
person.doCourt();
}
}
// 被代理的类
class Person implements Court{
private String name;
public Person(String name) {
this.name = name;
}
@Override
public void doCourt() {
System.out.println(name+"说:我没有杀人");
}
}
package com.msb.testProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
/**
* @Author: bingwoo
*/
public class Test1 {
public static void main(String[] args) {
Dinner dinner=new Person("张三");
// 通过Porxy动态代理获得一个代理对象,在代理对象中,对某个方法进行增强
//ClassLoader loader,被代理的对象的类加载器
ClassLoader classLoader = dinner.getClass().getClassLoader();
//Class>[] interfaces,被代理对象所实现的所有接口
Class[] interaces= dinner.getClass().getInterfaces();
//InvocationHandler h,执行处理器对象,专门用于定义增强的规则
InvocationHandler handler = new InvocationHandler(){
// invoke 当我们让代理对象调用任何方法时,都会触发invoke方法的执行
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//Object proxy, 代理对象
//Method method,被代理的方法
//Object[] args,被代理方法运行时的实参
Object res = null;
if(method.getName().equals("eat")){
System.out.println("饭前洗手");
// 让原有的eat的方法去运行
res =method.invoke(dinner, args);
System.out.println("饭后刷碗");
}else{
// 如果是其他方法,那么正常执行就可以了
res =method.invoke(dinner, args);
}
return res;
}
};
Dinner dinnerProxy =(Dinner) Proxy.newProxyInstance(classLoader,interaces,handler);
//dinnerProxy.eat("包子");
dinnerProxy.drink();
}
}
interface Dinner{
void eat(String foodName);
void drink();
}
class Person implements Dinner{
private String name;
public Person(String name) {
this.name = name;
}
@Override
public void eat(String foodName) {
System.out.println(name+"正在吃"+foodName);
}
@Override
public void drink( ) {
System.out.println(name+"正在喝茶");
}
}
class Student implements Dinner{
private String name;
public Student(String name) {
this.name = name;
}
@Override
public void eat(String foodName) {
System.out.println(name+"正在食堂吃"+foodName);
}
@Override
public void drink( ) {
System.out.println(name+"正在喝可乐");
}
}
代码示例:
package com.msb.testCglib;
import org.junit.Test;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* @Author: bingwoo
*/
public class Test1 {
@Test
public void testCglib(){
Person person =new Person();
// 获取一个Person的代理对象
// 1 获得一个Enhancer对象
Enhancer enhancer=new Enhancer();
// 2 设置父类字节码
enhancer.setSuperclass(person.getClass());
// 3 获取MethodIntercepter对象 用于定义增强规则
MethodInterceptor methodInterceptor=new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
/*Object o, 生成之后的代理对象 personProxy
Method method, 父类中原本要执行的方法 Person>>> eat()
Object[] objects, 方法在调用时传入的实参数组
MethodProxy methodProxy 子类中重写父类的方法 personProxy >>> eat()
*/
Object res =null;
if(method.getName().equals("eat")){
// 如果是eat方法 则增强并运行
System.out.println("饭前洗手");
res=methodProxy.invokeSuper(o,objects);
System.out.println("饭后刷碗");
}else{
// 如果是其他方法 不增强运行
res=methodProxy.invokeSuper(o,objects); // 子类对象方法在执行,默认会调用父类对应被重写的方法
}
return res;
}
};
// 4 设置methodInterceptor
enhancer.setCallback(methodInterceptor);
// 5 获得代理对象
Person personProxy = (Person)enhancer.create();
// 6 使用代理对象完成功能
personProxy.eat("包子");
}
}
class Person {
public Person( ) {
}
public void eat(String foodName) {
System.out.println("张三正在吃"+foodName);
}
}
导入依赖
<dependencies>
<!--spring核心容器包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.5</version>
</dependency>
<!--spring切面包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.3.5</version>
</dependency>
<!--织入包 spring-aspects 已经导入该包,这里可以不导入-->
<!--<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>-->
<!--aop联盟包-->
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<!--Apache Commons日志包-->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<!--德鲁伊连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.22</version>
</dependency>
<!--Junit单元测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<scope>test</scope>
</dependency>
<!--lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>
</dependencies>
切入点表达式:
execution(* com.msb.dao.UserDaoImpl.add(..)) //指定切点为UserDaoImpl.add方法
execution(* com.msb.dao.UserDaoImpl.*(..)) //指定切点为UserDaoImpl.所有的方法
execution(* com.msb.dao.*.*(..)) //指定切点为dao包下所有的类中的所有的方法
execution(* com.msb.dao.*.add(..)) //指定切点为dao包下所有的类中的add的方法
execution(* com.msb.dao.*.add*(..)) //指定切点为dao包下所有的类中的add开头的方法
开启注解扫描和AOP切面编程自动生成代理对象配置
<?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:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
">
<!--spring 包扫描 -->
<context:component-scan base-package="com.msb"/>
<!--aop autoProxy 自动生成代理对象 -->
<aop:aspectj-autoproxy/>
</beans>
准备接口:UserDao和EmpDao
package com.msb.dao;
/**
* @Author: bingwoo
*/
public interface EmpDao {
int addEmp(Integer empno,String ename,String job);
}
package com.msb.dao;
/**
* @Author: bingwoo
*/
public interface UserDao {
int addUser(Integer userid,String username);
}
接口实现
package com.msb.dao.impl;
import com.msb.dao.UserDao;
import org.springframework.stereotype.Repository;
/**
* @Author: bingwoo
*/
@Repository
public class UserDaoImpl implements UserDao {
public int addUser(Integer userid,String username){
System.out.println("userdao add ... ...");
//int i =1/0;
return 1;
}
}
package com.msb.dao.impl;
import com.msb.dao.EmpDao;
import com.msb.dao.UserDao;
import org.springframework.stereotype.Repository;
/**
* @Author: bingwoo
*/
@Repository
public class EmpDaoImpl implements EmpDao {
public int addEmp(Integer empno,String ename,String job){
System.out.println("empDao add ... ...");
return 1;
}
}
准备切面
package com.msb.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.util.Arrays;
/**
* @Author: bingwoo
*/
@Component
@Aspect
public class DaoAspect {
//定义公共切点
@Pointcut("execution(* com.msb.dao.*.add*(..))")
public void addPointCut(){}
/*
* 前置通知: 切点方法执行之前先执行的功能
* 参数列表可以用JoinPoint接收切点对象
* 可以获取方法执行的参数
* */
@Before("addPointCut()")
public void methodBefore(JoinPoint joinPoint){
System.out.println("Before invoked");
}
/*
* 后置通知:方法执行之后要增强的功能
* 无论切点方法是否出现异常都会执行的方法
* 参数列表可以用JoinPoint接收切点对象
* */
@After("addPointCut()")
public void methodAfter(JoinPoint joinPoint){
System.out.println("After invoked");
}
/*
* 返回通知:切点方法正常运行结束后增强的功能
* 如果方法运行过程中出现异常,则该功能不运行
* 参数列表可以用 JoinPoint joinPoint接收切点对象
* 可以用Object res接收方法返回值,需要用returning指定返回值名称
* */
@AfterReturning( value = "addPointCut()",returning = "res")
public void methodAfterReturning(JoinPoint joinPoint,Object res){
System.out.println("AfterReturning invoked");
}
/*
* 异常通知:切点方法出现异常时运行的增强功能
* 如果方法运行没有出现异常,则该功能不运行
* 参数列表可以用Exception ex接收异常对象 需要通过throwing指定异常名称
* */
@AfterThrowing( value = "addPointCut()",throwing = "ex")
public void methodAfterThrowing(Exception ex){
System.out.println("AfterThrowing invoked");
}
/*环绕通知:在切点方法之前和之后都进行功能的增强
* 需要在通知中定义方法执行的位置,并在执行位置之前和之后自定义增强的功能
* 方法列表可以通过ProceedingJoinPoint获取执行的切点
* 通过proceedingJoinPoint.proceed()方法控制切点方法的执行位置
* proceedingJoinPoint.proceed()方法会将切点方法的返回值获取到,并交给我们,可以做后续处理
* 我们在环绕通知的最后需要将切点方法的返回值继续向上返回,否则切点方法在执行时接收不到返回值
* */
@Around("addPointCut()")
public Object methodAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("aroundA invoked");
Object proceed = proceedingJoinPoint.proceed();
System.out.println("aroundB invoked");
return proceed;
}
}
测试代码
@Test
public void test1(){
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = context.getBean( UserDao.class);
int add = userDao.addUser(10,"晓明");
}
@Component
@Aspect
@Order(1)
public class userTest{
}
@Component
@Aspect
@Order(2)
public class userTest{
}
示例代码
package com.msb.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
/**
* @Author: bingwoo
*/
@Configuration
@ComponentScan(basePackages = "com.msb")
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class SpringConfig {
}
测试代码
@Test
public void test2(){
ApplicationContext context=new AnnotationConfigApplicationContext(SpringConfig.class);
UserDao userDao = context.getBean( UserDao.class);
int add = userDao.addUser(10,"晓明");
}
创建两个类,增强类和被增强类,创建方法
在spring配置文件中创建两个类对象
<!--创建对象-->
<bean id="userDao" class="com.com.msb.UserDaoImpl"></bean>
<bean id="daoAspect" class="com.com.aspect.DaoAspect"></bean>
在spring配置文件中配置切入点
<!--配置aop增强-->
<aop:config>
<!--切入点-->
<aop:pointcut id="pointCutAdd" expression="execution(* com.msb.dao.UserDao.add*(..))"/>
<!--配置切面-->
<aop:aspect ref="daoAspect">
<!--增强作用在具体的方法上-->
<aop:before method="methodBefore" pointcut-ref="pointCutAdd"/>
<aop:after method="methodAfter" pointcut-ref="pointCutAdd"/>
<aop:around method="methodAround" pointcut-ref="pointCutAdd"/>
<aop:after-returning method="methodAfterReturning" pointcut-ref="pointCutAdd" returning="res"/>
<aop:after-throwing method="methodAfterThrowing" pointcut-ref="pointCutAdd" throwing="ex"/>
</aop:aspect>
</aop:config>
<dependencies>
<!--spring核心容器包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.5</version>
</dependency>
<!--spring切面包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.3.5</version>
</dependency>
<!--aop联盟包-->
<dependency>
<groupId>aopalliance</groupId>
<artifactId>aopalliance</artifactId>
<version>1.0</version>
</dependency>
<!--德鲁伊连接池-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.22</version>
</dependency>
<!--springJDBC包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.5</version>
</dependency>
<!--spring事务控制包-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.3.5</version>
</dependency>
<!--spring orm 映射依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>5.3.5</version>
</dependency>
<!--Apache Commons日志包-->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<!--Junit单元测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<scope>test</scope>
</dependency>
<!--lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>
</dependencies>
jdbc_username=root
jdbc_password1=root
jdbc_driver=com.mysql.cj.jdbc.Driver
jdbc_url=jdbc:mysql://127.0.0.1:3306/mydb?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
<?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:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
">
<!--spring 注解扫描-->
<context:component-scan base-package="com.msb"/>
<!--读取jdbc配置文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--配置德鲁伊连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="username" value="${jdbc_username}"></property>
<property name="password1" value="${jdbc_password1}"></property>
<property name="url" value="${jdbc_url}"></property>
<property name="driverClassName" value="${jdbc_driver}"></property>
</bean>
<!--配置JDBCTemplate对象,并向里面注入DataSource-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!--通过set方法注入连接池-->
<property name="dataSource" ref="dataSource"></property>
</bean>
</beans>
package com.msb.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
/**
* @Author: bingwoo
*/
@AllArgsConstructor
@NoArgsConstructor
@Data
public class Emp implements Serializable{
private Integer empno;
private String ename;
private String job;
private Integer mgr;
private Date hiredate;
private Double sal;
private Double comm;
private Integer deptno;
}
package com.msb.service;
import com.msb.pojo.Emp;
import java.util.List;
/**
* @Author: bingwoo
*/
public interface EmpService {
int findEmpCount();
Emp findByEmpno(int empno);
List<Emp> findByDeptno(int deptno);
int addEmp(Emp emp);
int updateEmp(Emp emp);
int deleteEmp( int empno);
}
package com.msb.service.impl;
import com.msb.dao.EmpDao;
import com.msb.pojo.Emp;
import com.msb.service.EmpService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* bingwoo
*/
@Service
public class EmpServiceImpl implements EmpService {
@Autowired
private EmpDao empDao;
@Override
public int findEmpCount() {
return empDao.findEmpCount();
}
@Override
public Emp findByEmpno(int empno) {
return empDao.findByEmpno( empno);
}
@Override
public List<Emp> findByDeptno(int deptno) {
return empDao.findByDeptno( deptno);
}
@Override
public int addEmp(Emp emp) {
return empDao.addEmp(emp);
}
@Override
public int updateEmp(Emp emp) {
return empDao.updateEmp(emp);
}
@Override
public int deleteEmp(int empno) {
return empDao.deleteEmp(empno);
}
}
package com.msb.dao;
import com.msb.pojo.Emp;
import java.util.List;
/**
* @Author: bingwoo
*/
public interface EmpDao {
int findEmpCount();
Emp findByEmpno(int empno);
List<Emp> findByDeptno(int deptno);
int addEmp(Emp emp);
int updateEmp(Emp emp);
int deleteEmp(int empno);
}
package com.msb.dao.impl;
import com.msb.dao.EmpDao;
import com.msb.pojo.Emp;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
/**
* @Author: bingwoo
*/
@Repository
public class EmpDaoImpl implements EmpDao {
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public int findEmpCount() {
/*查询员工个数
* queryForObject 两个参数
* 1 SQL语句
* 2 返回值类型
*
* */
Integer empCount = jdbcTemplate.queryForObject("select count(1) from emp", Integer.class);
return empCount;
}
@Override
public Emp findByEmpno(int empno) {
/*
* 查询单个员工对象
* queryForObject三个参数
* 1 SQL语句
* 2 RowMapper接口的实现类对象,用于执行返回的结果用哪个类来进行封装 ,实现类为BeanPropertyRowMapper
* 3 SQL语句中需要的参数 (可变参数)
* */
BeanPropertyRowMapper<Emp> rowMapper =new BeanPropertyRowMapper<>(Emp.class);
Emp emp = jdbcTemplate.queryForObject("select * from emp where empno =?", rowMapper, empno);
return emp;
}
@Override
public List<Emp> findByDeptno(int deptno) {
/*
* 查询单个员工对象
* query三个参数
* 1 SQL语句
* 2 RowMapper接口的实现类对象,用于执行返回的结果用哪个类来进行封装 ,实现类为BeanPropertyRowMapper
* 3 SQL语句中需要的参数 (可变参数)
* */
BeanPropertyRowMapper<Emp> rowMapper =new BeanPropertyRowMapper<>(Emp.class);
List<Emp> emps = jdbcTemplate.query("select * from emp where deptno =?", rowMapper, deptno);
return emps;
}
@Override
public int addEmp(Emp emp) {
/*增删改
* 统统用update方法 两个参数
* 1 SQL语句
* 2 SQL语句需要的参数 (可变参数)
*
* */
String sql ="insert into emp values(DEFAULT ,?,?,?,?,?,?,?)";
Object[] args ={emp.getEname(),emp.getJob(),emp.getMgr(),emp.getHiredate(),emp.getSal(),emp.getComm(),emp.getDeptno()};
return jdbcTemplate.update(sql,args);
}
@Override
public int updateEmp(Emp emp) {
String sql ="update emp set ename =? , job =?, mgr=? , hiredate =?, sal=?, comm=?, deptno =? where empno =?";
Object[] args ={emp.getEname(),emp.getJob(),emp.getMgr(),emp.getHiredate(),emp.getSal(),emp.getComm(),emp.getDeptno(),emp.getEmpno()};
return jdbcTemplate.update(sql,args);
}
@Override
public int deleteEmp(int empno) {
String sql ="delete from emp where empno =?";
return jdbcTemplate.update(sql, empno);
}
}
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.Date;
import java.util.List;
/**
* @Author: bingwoo
*/
public class Test1 {
@Test
public void testEmpService(){
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
EmpService empService = context.getBean(EmpService.class);
// 查询员工个数
int empCount = empService.findEmpCount();
System.out.println(empCount);
// 根据员工编号查询员工对象
Emp byEmpno = empService.findByEmpno(7521);
System.out.println(byEmpno);
/*根据部门编号查询多个员工对象集合*/
List<Emp> emps = empService.findByDeptno(20);
emps.forEach(System.out::println);
/*增加员工信息*/
int rows = empService.addEmp(new Emp(null, "TOM", "SALESMAN", 13, new Date(), 2000.0, 100.0, 10));
System.out.println(rows);
/*根据员工编号修改员工信息*/
int rows = empService.updateEmp(new Emp(12, "JERRY", "MANAGER", 7839, new Date(), 3000.0, 0.0, 20));
System.out.println(rows);
/*根据员工编号删除员工信息*/
int rows = empService.deleteEmp(7939);
System.out.println(rows);
}
}
package com.msb.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* @Author: bingwoo
*/
@AllArgsConstructor
@NoArgsConstructor
@Data
public class Dept implements Serializable {
private Integer deptno;
private String dname;
private String loc;
}
package com.msb.service;
import com.msb.pojo.Dept;
import java.util.List;
/**
* @Author: bingwoo
*/
public interface DeptService {
int[] deptBatchAdd(List<Dept> depts);
int[] deptBatchUpdate(List<Dept> depts);
int[] deptBatchDelete(List<Integer> deptnos);
}
package com.msb.service.impl;
import com.msb.dao.DeptDao;
import com.msb.pojo.Dept;
import com.msb.service.DeptService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @Author: bingwoo
*/
@Service
public class DeptServiceImpl implements DeptService {
@Autowired
private DeptDao deptDao;
@Override
public int[] deptBatchAdd(List<Dept> depts) {
return deptDao.deptBatchAdd(depts);
}
@Override
public int[] deptBatchUpdate(List<Dept> depts) {
return deptDao.deptBatchUpdate(depts);
}
@Override
public int[] deptBatchDelete(List<Integer> deptnos) {
return deptDao.deptBatchDelete(deptnos);
}
}
package com.msb.dao;
import com.msb.pojo.Dept;
import java.util.List;
/**
* @Author: bingwoo
*/
public interface DeptDao {
int[] deptBatchAdd(List<Dept> depts);
int[] deptBatchUpdate(List<Dept> depts);
int[] deptBatchDelete(List<Integer> deptnos);
}
package com.msb.dao.impl;
import com.msb.dao.DeptDao;
import com.msb.pojo.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import java.util.LinkedList;
import java.util.List;
/**
* @Author: bingwoo
*/
@Repository
public class DeptDaoImpl implements DeptDao {
@Autowired
private JdbcTemplate jdbcTemplate;
@Override
public int[] deptBatchAdd(List<Dept> depts) {
String sql ="insert into dept values(DEFAULT,?,?)";
List<Object[]> args =new LinkedList<>();
for (Dept dept : depts) {
Object[] arg ={dept.getDname(),dept.getLoc()};
args.add(arg);
}
return jdbcTemplate.batchUpdate(sql, args);
}
@Override
public int[] deptBatchUpdate(List<Dept> depts) {
String sql ="update dept set dname =? ,loc =? where deptno=?";
List<Object[]> args =new LinkedList<>();
for (Dept dept : depts) {
Object[] arg ={dept.getDname(),dept.getLoc(),dept.getDeptno()};
args.add(arg);
}
return jdbcTemplate.batchUpdate(sql, args);
}
@Override
public int[] deptBatchDelete(List<Integer> deptnos) {
String sql ="delete from dept where deptno =?";
List<Object[]> args =new LinkedList<>();
for (Integer deptno : deptnos) {
Object[] arg ={deptno};
args.add(arg);
}
return jdbcTemplate.batchUpdate(sql, args);
}
}
package com.msb.test;
import com.msb.pojo.Dept;
import com.msb.service.DeptService;
import com.msb.service.EmpService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* @Author: bingwoo
*/
public class Test2 {
@Test
public void testBatchAdd(){
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
DeptService deptService = context.getBean(DeptService.class);
List<Dept> depts =new ArrayList<>();
for (int i = 0; i < 10; i++) {
depts.add(new Dept(null,"name"+i,"loc"+i));
}
int[] ints = deptService.deptBatchAdd(depts);
System.out.println(Arrays.toString(ints));
}
@Test
public void testBatchUpdate(){
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
DeptService deptService = context.getBean(DeptService.class);
List<Dept> depts =new ArrayList<>();
for (int i = 51; i <=60; i++) {
depts.add(new Dept(i,"newname","newLoc"));
}
int[] ints = deptService.deptBatchUpdate(depts);
System.out.println(Arrays.toString(ints));
}
@Test
public void testBatchDelete(){
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
DeptService deptService = context.getBean(DeptService.class);
List<Integer> deptnos =new ArrayList<>();
for (int i = 51; i <=69; i++) {
deptnos.add(i);
}
int[] ints = deptService.deptBatchDelete(deptnos);
System.out.println(Arrays.toString(ints));
}
}
<?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:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
">
<!--spring 注解扫描-->
<context:component-scan base-package="com.msb"/>
<!--读取jdbc配置文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--配置德鲁伊连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="username" value="${jdbc_username}"></property>
<property name="password1" value="${jdbc_password1}"></property>
<property name="url" value="${jdbc_url}"></property>
<property name="driverClassName" value="${jdbc_driver}"></property>
</bean>
<!--配置JDBCTemplate对象,并向里面注入DataSource-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!--通过set方法注入连接池-->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--配置一个事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--将数据源注入事务管理器-->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--开启事务注解-->
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
package com.msb.service.impl;
import com.msb.dao.AccountDao;
import com.msb.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* @Author: bingwoo
*/
@Service
//@Transactional //加在类上,代表类中的所有方法都添加了事务控制
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
@Override
@Transactional// 放在方法上,就是仅仅对当前方法增加了事务控制
public int transMoney(int from, int to, int money) {
int rows=0;
rows+=accountDao.transMoney(from, 0 - money);
int i =1/0;
rows+=accountDao.transMoney(to, money);
return rows;
}
}
@Transactional 注解的一些参数和参数的含义
@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.READ_UNCOMMITTED,readOnly = true,rollbackFor = ClassCastException.class,noRollbackFor = NullPointerException.class,timeout = 10)
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
@AliasFor("transactionManager")
String value() default "";
@AliasFor("value")
String transactionManager() default "";
String[] label() default {};
Propagation propagation() default Propagation.REQUIRED;
Isolation isolation() default Isolation.DEFAULT;
int timeout() default -1;
String timeoutString() default "";
boolean readOnly() default false;
Class<? extends Throwable>[] rollbackFor() default {};
String[] rollbackForClassName() default {};
Class<? extends Throwable>[] noRollbackFor() default {};
String[] noRollbackForClassName() default {};
}
propagation 事务的传播行为(面试)
多事务方法之间调用,事务是如何管理的
事务传播行为类型 | 说明 |
---|---|
PROPAGATION_REQUIRED | 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择(默认)。 |
PROPAGATION_SUPPORTS | 支持当前事务,如果当前没有事务,就以非事务方式执行。 |
PROPAGATION_MANDATORY | 使用当前的事务,如果当前没有事务,就抛出异常。 |
PROPAGATION_REQUIRES_NEW | 新建事务,如果当前存在事务,把当前事务挂起。 |
PROPAGATION_NOT_SUPPORTED | 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 |
以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 | 以非事务方式执行,如果当前存在事务,则抛出异常。 |
PROPAGATION_NESTED | 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。 |
如果service层 add方法调用了 addDept和addEmp两个方法
PROPAGATION_REQUIRED
PROPAGATION_REQUIRES_NEW
DEFAULT (默认):这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别。另外四个与JDBC的隔离级别相对应。MySQL默认REPEATABLE_READ,Oracle默认READ_COMMITTED。
READ_UNCOMMITTED (读未提交) :这是事务最低的隔离级别,它允许另外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻像读。
READ_COMMITTED (读已提交) :保证一个事务修改的数据提交后才能被另外一个事务读取,另外一个事务不能读取该事务未提交的数据。这种事务隔离级别可以避免脏读出现,但是可能会出现不可重复读和幻像读。
REPEATABLE_READ (可重复读) :这种事务隔离级别可以防止脏读、不可重复读,但是可能出现幻像读。它除了保证一个事务不能读取另一个事务未提交的数据外,还保证了不可重复读。
SERIALIZABLE(串行化) :这是花费最高代价但是最可靠的事务隔离级别,事务被处理为顺序执行。除了防止脏读、不可重复读外,还避免了幻像读。
timeout 超时时间:事务一定要在多长时间之内提交,如果不提交就会回滚
readOnly 只读事务:事务是否只能读取数据库的数据,如果为true,则不允许进行增删改
rollbackFor 指定发生回滚的异常:当方法发生哪些异常时才会回滚
noRollbackFor 指定不发生回滚的异常:当方法发生哪些异常时,不会回滚
<?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:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
">
<context:component-scan base-package="com.msb"/>
<!--读取jdbc配置文件-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!--配置德鲁伊连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="username" value="${jdbc_username}"></property>
<property name="password1" value="${jdbc_password1}"></property>
<property name="url" value="${jdbc_url}"></property>
<property name="driverClassName" value="${jdbc_driver}"></property>
</bean>
<!--配置JDBCTemplate对象,并向里面注入DataSource-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!--通过set方法注入连接池-->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--配置一个事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--将数据源注入事务管理器-->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--配置通知-->
<tx:advice id="txAdvice">
<!--配置事务参数-->
<tx:attributes>
<tx:method name="transMoney" isolation="DEFAULT" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!--配置AOP-->
<aop:config>
<!--配置切入点-->
<aop:pointcut id="pt" expression="execution(* com.msb.service.AccountService.transMoney(..))"/>
<!--配置切面-->
<aop:advisor advice-ref="txAdvice" pointcut-ref="pt"></aop:advisor>
</aop:config>
</beans>
Spring 框架整理知识点,其中主要的知识点在于IOC 控制反转和AOP切面编程,Beand的生命周期,事务的特性及隔离级别。这些都是最基础,而且必须要知道的。这里把必须掌握的知识点汇总一下,方便以后查阅。如发现问题请留言指正,我会及时更新,期待与大家共同进步!