Spring学习记录重点

Spring框架是一个容器,整合其他框架的框架,核心是IOC和AOP,由20多个模块组成
Spring为了解决企业级应用开发的复杂性创建的 简化开发
Spring的特点:

1.轻量级:由20多个模块构成,每个jar包都很小,核心包3M左右,对代码无污染
2.面向接口编程:灵活性,可扩展性,维护性都极高,使用时接口指向实现类,切换实现类即可切换整个功能
3.AOP:面向切面编程,就是将公共的通用的重复的代码单独开发,需要的时候给回去,底层的原理是动态代理
4.整合其他框架:整合后其他框架更好用

控制反转IOC(Inversion of Control)是一个概念,是一种思想。由spring容器进行对象的创建和依赖注入

正转:由程序员进行对象的创建和依赖注入称为正转,程序员说了算
反转:由spring创建对象和依赖注入,将控制权从程序员手中夺走,给spring容器,称为反转

基于xml的IOC

 1.创建对象
    <!--bean的id属性就是要创建的对象的名称,class属性是要创建的对象的类型,底层通过反射构建对象-->
        <bean id="stu" class="com.lv.pojo.Student"></bean>
    2.给创建的对象赋值
        A.使用setter注入
            注入分为简单类型注入和引用类型注入
            简单类型使用value属性
            引用类型使用ref属性
            使用setter注入实体类里必须提供无参构造方法,必须提供set方法
              <bean id="school" class="com.lv.pojo2.School">
                     <property name="name" value="清华大学"></property>
                     <property name="address" value="北京海淀区"></property>
                 </bean>
                 <bean id="stu" class="com.lv.pojo2.Student">
                     <property name="name" value="李四"></property> ---->简单类型注入
                     <property name="age" value="22"></property>
                     <property name="school" ref="school"></property> ---->引用类型注入
                 </bean>

        B.使用构造方法注入
            a.使用构造方法的参数名称进行注入值
              <bean id="school" class="com.lv.pojo3.School">
                    <constructor-arg name="name" value="清华大学"></constructor-arg>
                    <constructor-arg name="address" value="海淀区"></constructor-arg>
              </bean>
            b.使用构造方法的参数下标注入值
               <bean id="stu" class="com.lv.pojo3.Student">
                    <constructor-arg index="0" value="老三"></constructor-arg>
                    <constructor-arg index="1" value="22"></constructor-arg>
                    <constructor-arg index="2" ref="school"></constructor-arg>
               </bean>
            c.使用默认的构造方法的参数的顺序注入值
            <bean id="stu1" class="com.lv.pojo3.Student">
                    <constructor-arg value="老四"></constructor-arg>
                    <constructor-arg value="22"></constructor-arg>
                    <constructor-arg ref="school"></constructor-arg>
             </bean>

项目案例
使用三层架构进行用户的插入操作 (界面层,业务逻辑层,数据访问层)
Spring会接管三层架构中哪些对象的创建?

非Spring接管的三层项目构建:

    实体类 Users
    public class Users {
        private int uid;
        private String uname;
        private  int uage;
        public Users() {
        }
        public Users(int uid, String uname, int uage) {
            this.uid = uid;
            this.uname = uname;
            this.uage = uage;
        }
        @Override
        public String toString() {
            return "Users{" +
                    "uid=" + uid +
                    ", uname='" + uname + '\'' +
                    ", uage=" + uage +
                    '}';
        }
        public int getUid() {
            return uid;
        }
        public void setUid(int uid) {
            this.uid = uid;
        }
        public String getUname() {
            return uname;
        }
        public void setUname(String uname) {
            this.uname = uname;
        }
        public int getUage() {
            return uage;
        }
        public void setUage(int uage) {
            this.uage = uage;
        }
    }

   数据访问层 UsersMapper.java接口  UsersMapperImpl.java实现类
    public interface UsersMapper {
        int insert(Users u);
    }
    public class UsersMapperImpl implements UsersMapper{
        @Override
        public int insert(Users u) {
            System.out.println(u.getUname()+"用户增加成功!");
            return 1;
        }
    }

   业务逻辑层 UsersService.java接口  UsersServiceImpl.java实现类
    public interface UsersService {
        int insert(Users users);
    }
    public class UsersServiceImpl implements UsersService {
        //在所有的业务逻辑层中都必定有数据访问层的对象
        private UsersMapper usersMapper = new UsersMapperImpl();
        @Override
        public int insert(Users users) {
            return usersMapper.insert(users);
        }
    }

   界面层     UsersController.java类
    public class UsersController {
        //访问业务逻辑层,就是创建对象(所有的界面层都会有业务逻辑层的对象) 接口指向实现类
        public UsersService usersService = new UsersServiceImpl();
        //对外提供访问的功能
        public int insert(Users users){
            return usersService.insert(users);
        }
    }

   测试类
    public class Mytest {
        @Test
        public void testA(){
            UsersController usersController = new UsersController();
            int num = usersController.insert(new Users(001,"张三",22));
            System.out.println(num);
        }
    }

Spring用xml更改的三层项目构建:

 applicationContext.xml文件
      <!--创建数据访问层的对象-->
        <bean id="umapper" class="com.lv.dao.UsersMapperImpl"></bean>
        <!--创建业务逻辑层的对象-->
        <bean id="uservice" class="com.lv.service.impl.UsersServiceImpl">
            <property name="usersMapper" ref="umapper"></property>
        </bean>
        <!--创建界面层的对象-->
        <bean id="ucontroller" class="com.lv.controller.UsersController">
            <property name="usersService" ref="uservice"></property>
        </bean>

   业务逻辑层 UsersService.java接口  UsersServiceImpl.java实现类
    public class UsersServiceImpl implements UsersService {
        //在所有的业务逻辑层中都必定有数据访问层的对象
        private UsersMapper usersMapper; //= new UsersMapperImpl();
        //给spring创建对象提供set方法
        public void setUsersMapper(UsersMapper usersMapper) {
            this.usersMapper = usersMapper;
        }
        @Override
        public int insert(Users users) {
            return usersMapper.insert(users);
        }
    }

   界面层     UsersController.java类
    public class UsersController {
        //访问业务逻辑层,就是创建对象(所有的界面层都会有业务逻辑层的对象) 接口指向实现类
        public UsersService usersService ;//= new UsersServiceImpl();
        //给spring创建对象提供set方法
        public void setUsersService(UsersService usersService) {
            this.usersService = usersService;
        }
        //对外提供访问的功能
        public int insert(Users users){
            return usersService.insert(users);
        }
    }

   测试类
    public class Mytest {
        @Test
        public void testA(){
            //创建容器并启动
            ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
            //取出对象
            UsersController usersController = (UsersController) ac.getBean("ucontroller");
            //测试功能
            int num = usersController.insert(new Users(001,"王五",24));
            System.out.println(num);
        }
    }

基于注解的IOC
也称为DI(Dependency Injection),它是IOC的具体实现技术
基于注解的IOC,必须要在Spring核心配置文件中添加包扫描

  <context:component-scan base-package="com.lv.s01"></context:component-scan>

1.创建对象的注解

@Component:可以创建任意对象 @Component(“stu”)指定名称为stu
@Controller:专门用来创建控制器的对象,可以接受用户请求,可以返回处理结果给客户端
@Service:专门用来创建业务逻辑层的对象,负责向下访问数据访问层,处理完毕后的结果返回给界面层
@Repository:专门用来创建数据访问层的对象,负责数据库中的增删改查

2.依赖注入的注解

简单类型的注入
@Value:用来给简单类型注入值 @Value(“张三”)
引用类型的注入
@Autowired:使用类型注入值,从整个Bean工厂中搜索同源类型的对象进行注入
同源类型也可注入
@Autowired
@Qualifier:使用名称注入值,从整个Bean工厂中搜索相同名称的对象进行注入 @Qualifier(“school”)

为应用指定多个Spring配置文件

 1.按层拆
 2.按功能拆
批量导入配置文件
<import resource="applicationContext_*.xml"></import>

AspectJ框架,面向切面的框架,扩展了Java语言,提供强大的切面实现
AspectJ常用的通知

 1.前置通知@Before
    @Aspect //交给AspectJ的框架去识别切面类
    @Component //创建对象
    public class MyAspect {
   /* //所有切面的功能都是由切面方法实现
    //前置通知的切面方法规范
    1.访问权限是public
    2.方法的返回值是void
    3.方法名称自定义
    4.方法无参,有的话只能是JoinPoint类型
    5.必须使用@Before注解声音切入时机和切入点
    参数value:指定切入点表达式
    */
   @Before(value = "execution(* com.lv.s01.*.*(..))")
    public void MyBefore(){
        System.out.println("切面方法的前置通知功能实现");
    }
    }

   2.后置通知@AfterReturning
    @Aspect
    @Component
    public class MyAspect {
        //后置通知的方法规范
        // 1.访问权限是public
        // 2.方法没有返回值void
        // 3.名称自定义
        // 4.方法有参数
        //value属性指定切入点表达式 returning指定目标方法的返回值的名称,名称必须与切面方法的参数名称一致
        @AfterReturning(value ="execution(* com.lv.s02.*.*(..))" ,returning = "obj")
        public void myAfterReturning(Object obj){
            System.out.println("后置通知功能实现");
            if(obj != null){
                if(obj instanceof String){
                    //把业务代码的返回值小写转大写
                    obj = obj.toString().toUpperCase();
                    System.out.println("在切面方法中目标方法的返回值:"+obj);
                }
                if (obj instanceof Student){
                    Student stu = (Student) obj;
                    stu.setName("李四");
                    System.out.println("在切面方法中目标方法的返回值:"+stu);
                }
            }
        }
    }
    3.环绕通知@Around
    通过拦截目标方法的方式,在目标方法前后增强功能的通知
    @Aspect
    @Component
    public class MyAspect {
        //环绕通知方法的规范
        // 访问权限是public
        // 有返回值,就是目标方法的返回值
        // 名称自定义
        // 方法有参数,此参数就是目标方法,回避异常
        //value:指定切入点表达式
        //ProceedingJoinPoint 底层就是调用目标方法
        @Around(value = "execution(* com.lv.s03.*.*(..))")
        public Object myAround(ProceedingJoinPoint pjt) throws Throwable {
            //前切功能实现
            System.out.println("环绕通知的前切功能实现");
            //目标方法调用
            Object obj = pjt.proceed(pjt.getArgs());
            //后切功能实现
            System.out.println("环绕通知的后切功能实现");
            return obj.toString().toUpperCase();//改变了目标方法的返回值
        }
    }

   4.最终通知@After
    无论目标方法是否正常执行,最终通知都会被执行
    @Aspect
    @Component
    public class MyAspect {
        //最终通知方法的规范
        // 访问权限是public
        // 方法没有返回值
        // 名称自定义
        // 方法没有参数,如果有只能是JoinPoint
        //value:指定切入点表达式
        @After(value = "execution(* com.lv.s04.*.*(..))")
        public void myAfter(){
            //最终通知功能实现
            System.out.println("最终通知的功能实现");
        }
    }

   5.定义切入点名称@Pointcut
    @Pointcut(value = "execution(* com.lv.s04.*.*(..))")
        public void myPointcut(){}

AspectJ切入点表达式(重点):

execution(访问权限 方法返回值 方法声明(参数) 异常类型)
* 代表任意字符
.. 如果出现在方法的参数中代表任意参数,如果出现在路径中代表本路径及其所有的子路径
execution(public * *(..)) 任意公共方法
execution(* set*(..)) 任意一个set开始的方法
execution(* com.xyz.service.impl.*.*(..)) 任意方法返回值,在com.xyz.service.impl的任意类里面的任意方法的任意参数
execution(* com.xyz.service..*.*(..)) 任意方法返回值,在com.xyz.service包下任意路径的任意类里面的任意方法的任意参数
execution(* *..service.*.*(..)) 任意方法返回值,任意包下的任意路径的service包里的任意类里面的任意方法的任意参数
execution(* *.service.*.*(..)) 任意方法返回值,任意 一级包下的service包里的任意类里面的任意方法的任意参数

AspectJ框架切换JDK动态代理和CGLib动态代理:

  JDK动态代理:<aop:aspectj-autoproxy></aop:aspectj-autoproxy> 只能用接口
  CGlib:<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy> 可以用接口和实现类
  用接口来接不会出错

SM整合项目重点
applicationContext_mapper.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: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 https://www.springframework.org/schema/context/spring-context.xsd">
            <!--读取jdbc属性文件-->
            <context:property-placeholder location="jdbc.properties"></context:property-placeholder>
            <!--创建数据源-->
            <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
                <property name="driverClassName" value="${jdbc.driverClassName}"></property>
                <property name="url" value="${jdbc.url}"></property>
                <property name="username" value="${jdbc.username}"></property>
                <property name="password" value="${jdbc.password}"></property>
            </bean>
            <!--配置SqlSessionFactoryBean-->
            <bean class="org.mybatis.spring.SqlSessionFactoryBean">
                <!--配置数据源-->
                <property name="dataSource" ref="dataSource"></property>
                <!--配置Mybatis的核心配置文件-->
                <property name="configLocation" value="SqlMapConfig.xml"></property>
                <!--注册实体类的别名-->
                <property name="typeAliasesPackage" value="com.lv.pojo"></property>
            </bean>
            <!--注册mapper.xml文件MapperScannerConfigurer-->
                <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
                    <property name="basePackage" value="com.lv.mapper"></property>
                </bean>
    </beans>

applicationContext_service.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:context="http://www.springframework.org/schema/context" 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/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
    <!--导入applicationContext_mapper.xml-->
    <import resource="applicationContext_mapper.xml"></import>
    <!--SM基于注解的开发,添加包扫描-->
    <context:component-scan base-package="com.lv.service.impl"></context:component-scan>
    <!--事务处理-->
    <!--添加事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--事务必须关联数据库处理,需要配置数据源-->
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!--添加事务的注解驱动 后缀是tx-->
    <tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
</beans>

@Transactional注解参数详解

  @Transactional(propagation = Propagation.REQUIRED,noRollbackForClassName = "ArithmeticException",timeout = -1,readOnly = false,isolation = Isolation.DEFAULT)
    //propagation:事务的传播特性
    //noRollbackForClassName:指定发生异常的名称不回滚,
    //rollbackForClassName:指定发生什么异常必须回滚
    //timeout:连接超时设置,默认-1表示永不超时
    //readOnly:默认是false,如果是查询操作必须为true
    //isolation = Isolation.DEFAULT:使用当前数据库的隔离级别

Spring的两种事务处理方式

1.注解式的事务
2.声明式事务(重点)
要求项目中的方法命名有规范
1.增加操作需要包含add,save,insert,set
2.更新操作需要包含update,change,modify
3.删除操作需要包含delete,drop,remove,clear
4.查询操作需要包含select,find,search,get

applicationContext_trans.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:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
           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/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
        <!--此配置文件与applicationContext_service.xml功能一样,事务配置不同-->
        <!--导入applicationContext_mapper.xml-->
        <import resource="applicationContext_mapper.xml"></import>
        <!--添加包扫描-->
        <context:component-scan base-package="com.lv.service.impl"></context:component-scan>
        <!--添加事务管理器-->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
            <property name="dataSource" ref="dataSource"></property>
        </bean>
        <!--配置事务切面 后缀tx-->
        <tx:advice id="myadvice" transaction-manager="transactionManager">
            <tx:attributes>
                <tx:method name="*select*" read-only="true"/>
                <tx:method name="*find*" read-only="true"/>
                <tx:method name="*search*" read-only="true"/>
                <tx:method name="*get*" read-only="true"/>
                <tx:method name="*insert*" propagation="REQUIRED"/>
                <tx:method name="*add*" propagation="REQUIRED"/>
                <tx:method name="*save*" propagation="REQUIRED"/>
                <tx:method name="*update*" propagation="REQUIRED"/>
                <tx:method name="*change*" propagation="REQUIRED"/>
                <tx:method name="*delete*" propagation="REQUIRED"/>
                <tx:method name="*remove*" propagation="REQUIRED"/>
                <tx:method name="*drop*" propagation="REQUIRED"/>
                <tx:method name="*clear*" propagation="REQUIRED"/>
                <tx:method name="*" propagation="SUPPORTS"/>
            </tx:attributes>
        </tx:advice>
        <!--绑定切面和切入点-->
        <aop:config>
            <aop:pointcut id="mycut" expression="execution(* com.lv.service.impl.*.*(..))"></aop:pointcut>
            <aop:advisor advice-ref="myadvice" pointcut-ref="mycut"></aop:advisor>
        </aop:config>
    </beans>

Spring中事务的五大隔离级别

1.未提交读(Read Uncommitted):允许脏读,也就是可能读取到其他会话中未提交事务修改的数据
2.提交读(Read Committed):只能读取到已经提交的数据。Oracle等多数数据库默认都是该级别 (不重复读)
3.可重复读(Repeated Read):可重复读。在同一个事务内的查询都是事务开始时刻一致的,InnoDB默认级别。在SQL标准中,该隔离级别消除了不可重复读,但是还存在幻象读,但是innoDB解决了幻读
4.串行读(Serializable):完全串行化的读,每次读都需要获得表级共享锁,读写相互都会阻塞
5.isolation = Isolation.DEFAULT:使用当前数据库的隔离级别
(重点MySQL的隔离级别是可重复读)
默认系统事务隔离级别是READ COMMITTED,也就是读已提交
MySQL:mysql默认的事务处理级别是’REPEATABLE-READ’,也就是可重复读
Oracle:oracle数据库支持READ COMMITTED 和 SERIALIZABLE这两种事务隔离级别。

事务管理器,项目所有事务必须添加到业务逻辑层!
如果使用Mybatis框架,必须使用DataSourceTransactionManager类完成处理

 <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--事务必须关联数据库处理,需要配置数据源-->
        <property name="dataSource" ref="dataSource"></property>
 </bean>

Spring事务的传播特性

多个事务之间的合并,互斥等都可以通过设置事务的传播特性来解决
常用
PROPAGATION_REQUIRED:必被包含事务(增删改必用)
PROPAGATION_REQUIRES_NEW:自己新开事务,不管之前是否有事务
PROPAGATION_SUPPORTS:支持事务,如果加入的方法有事务,则支持事务,如果没有,不单开事务
PROPAGATION_NEVER:不能运行中事务中,如果包在事务中,抛异常
PROPAGATION_NOT_SUPPORTED:不支持事务,运行在非事务的环境
不常用
PROPAGATION_MANDATORY:必须包在事务中,没有事务则抛异常
PROPAGATION_NESTED:嵌套事务

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值