一、Spring了解
Spring:程序员们的春天
- Spring主要技术是IOC、AOP两个大概念
- 它是轻量级的,每个jar包就1M ~ 3M 左右,所以速度快
- 面向接口编程:降低了耦合度
- 面向切面编程:增加了灵活性
- 不排斥其它框架,可以和任何框架整合到一起
二、IOC入门
2.1 IOC概念
IOC:控制反转,是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入,还有一种方式叫“依赖查找”。
IOC是一种设计思想,其实我们在学习Spring的时候,应该把注意力放在Spring的设计方式上,为什么要这么设计,这么设计的思想是什么。
控制反转:原本我们程序员需要自己new Student一个对象,但是现在反转了,我们将new Student这种操作交给Spring容器去处理,这就是控制反转,以后不需要我们手动的去new对象了
依赖注入:依赖注入就是我们在创建了对象以后,肯定要给对象的属性赋值啊,这种赋值的操作就是依赖注入,只是我们的赋值方式和以往略有不同。
2.1 创建对象
- 使用xml方式,通过bean标签来创建对象
<bean id="stu" class="com.meteor.pojo.Student"></bean> 这就相当于我们的 Student stu = new Student(); 已经创建出来了对象 id:是对象的名称 class:是对象类 //这就相当于我们把对象交给了spring容器处理,想用的时候就去容器种拿
- 我们来取一下对象,看看是如何使用的
//1.通过读取配置文件中的bean标签信息,已经创建出了对象 相当于Student stu = new Student(); //当读取applicationContext.xml配置文件信息时,会将其所有bean标签的对象都创建出来 ApplicationContext cpx = new ClassPathXmlApplicationContext("applicationContext.xml"); //2.通过bean标签中的id拿到对象 Student stu = (Student) cpx.getBean("stu");
2.2 使用setter赋值
- 我们的类对象,必须有set()方法
- 必须拥有无参构造方法
- 我们用的标签是property
简单类型的注入:
<!-- 创建学生对象 --> <bean id="stu" class="com.meteor.pojo.Student"> <property name="name" value="张三"/> <property name="age" value="21"/> </bean>
引用类型的注入:
<!-- 创建学生对象 --> <bean id="stu" class="com.meteor.pojo.Student"> <property name="name" value="张三"/> <property name="age" value="21"/> <property name="school" ref="sch"/> </bean> <bean id="sch" class="com.meteor.pojo.School"> <property name="name" value="hljdx"/> <property name="address" value="hlj"/> </bean> // 我们将Student、School两个对象都交给了spring容器管理,而引用类型的注入方式是通过ref属性,将school这个对象传到student里面
2.3 使用构造方法注入
- 必须拥有构造方法,你构造方法是几个参数,注入就几个参数
- 无需强制set()方法
- 我们用的标签是constructor-arg
<!-- 创建学生对象 --> <bean id="school" class="com.meteor.pojo2.School"> <--!--> name是构造方法的名称 </--!--> <constructor-arg name="name" value="hljdx"/> <constructor-arg name="address" value="hlj"/> </bean>
- 也可以通过参数下标来注入
<bean id="stu" class="com.meteor.pojo2.Student"> <constructor-arg index="0" value="hljdx"/> <constructor-arg index="1" value="20"/> <constructor-arg index="2" ref="school"/> </bean>
2.4 引用类型自动注入
刚刚我们已经介绍了引用类型通过ref属性注入,但是还可以通过另两种方式
byName:按照变量名称注入,spring容器会根据你原本类中的引用类型 public School school
这个school名称,自动去xml文件中搜索有没有这个同名id,如果有则进行注入。
byType:按照变量类型注入,spring容器会自动寻找School类型的class,一种类型只有一个对象。
-
java类中的成员变量的类型与xml文件中bean对象的类型一样
-
java类中的成员变量的类型与xml文件中bean对象的是父(java)子(xml)类型
-
若子类父类用默认得名称,则父类先注入。子类的构造方法会默认调用父类无参构造方法,清空数据嘛,然后再调用自己的构造方法。若子类父类改名了,则按名称注入。
-
java类中的成员变量的类型与xml文件中bean对象的类型是接口(java)与实现类
2.5 使用注解一体化IOC
//使用注解必须在xml文件中配置注解扫描器 <context:component-scan base-package="com.meteor.pojo3"/>
控制反转
- 我们使用xml时通过bean标签来创建对象,现在使用注解来代替
@Component public class Student { // 当我们在类上加入这个注解的时候,就相当于将对象放入了spring容器进行管理。但是此时并没有进行赋值操作, 如果我们不加入名称,则默认使用的是驼峰命名法 //并且Spring创建的对象是单例模式,无论我们使用多少次都是相同的对象
@Component: 可以创建任意对象
@Controller: 专门创建控制器的对象(Servlet),接受用户请求返回处理结果给客户端
@Service: 专门用来创建业务逻辑对象,访问数据层,处理完毕后返回给界面层
@Repository: 用来创建数据访问层的对象,负责增删改查
依赖注入
@Value: 给简单类型注入值
@Autowired: 使用类型注入值,从整个Bean工厂中搜索同源类型的对象,进行注入
@Autowired + @Qualifier : 使用名称注入值,如果单独使用Qualifier 是不会注入进来值得
@Resource: 自动注入,我个人挺喜欢用这个先按名称匹配,再按类型匹配Bean。
三、AOP入门
3.1 AOP概念
AOP: 在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
AOP面向切面编程,一般将公用的代码放入到切面中,例如日志、事务等等,减少了冗余的代码,降低了程序的耦合度。
3.2 常用AOP通知
-
切面:就是将重复的、可复用的代码提取出来
-
连接点:就是目标方法,因为我们需要知道是在目标方法 前 切面还是 后 切面
-
切入点:多个连接点构成了切入点
-
通知:指定切入时机
-
在Advice的时间,在Pointcut的位置,执行Aspect
-
@Before:前置通知,在目标方法之前执行,只能拿到目标方法的签名
-
@AfterRetunring:后置通知,在目标方法后执行,可以修改目标方法的返回值
-
@Around:环绕通知,这个最厉害,相当于前两者的结合,但是略有不同
-
@After:最终通知,无论程序挂没挂,这个都必须执行,一般用于释放资源
-
@AfterThrowing:异常通知,在目标方法执行发生了异常的时候,执行这个通知、
-
公式:execution(访问权限、返回类型、方法声明(参数))
-
在xml文件中加入切面的注解
<aop:aspectj-autoproxy/>
3.3 Before前置通知
@Aspect public class MyAspect { //定义方法,表示切面的具体功能 /* 前置通知方法的定义 1)方法是public 2)方法是void 3)方法名称自定义 4)方法可以有参数,如果有是JoinPoint @Before:前置通知 属性:value切入点表达式,表示切面的执行位置。 在这个方法时,会同时执行切面的功能 位置:在方法的上面 特点: 1)执行时间:在目标方法之前先执行的 2)不会影响目标方法的执行 3)不会修改目标方法的执行结果 */ @Before(value = "execution(public void com.meteor.service.impl.SomeServiceImpl.doSome(String, Integer))") public void myBefore() { System.out.println("前置通知,切面的功能在目标方法之前执行" + new Date()); } } //可以拥有一个方法参数JoinPoint jp,用来获取方法签名
3.4 @AfterRetunring后置通知
//通过returning来指定方法返回值得名称,必须与接收名称相同 //如果说我们传的是基本类型则无法改变结果,如果传的是引用类型则可以通过值进行修改。 @AfterReturning(value = "execution(* *..SomeServiceImpl.doOther(..))",returning = "res") public void myAfterReturning(Object res) { System.out.println("后置通知,在目标方法后执行的。" + res); }
3.5 @Around环绕通知(最重要)
* *..service.*.*(..) 代表任意权限方法下的 任意包下的 service包 下的 任意类中的任意方法的任意参数 // 返回类型推荐使用Object或者* @Aspect public class MyAspect { @Around(value = "execution(* *..SomeServiceImpl.doFirst(..))") public Object myAround(ProceedingJoinPoint pjp) throws Throwable { System.out.println("执行了myAround" + pjp); //执行目标方法 ProceedingJoinPoint表示 doFirst Object proceed = pjp.proceed(); // method.invoke(),表示执行doFirst()方法本身 //return "HelloAround,不是目标方法的执行结果"; //返回目标方法执行结果,没有修改的 return proceed; } }
- 如果你细心的去将所有通知一起加入进来,那么你会发现其实并不是@After 通知在最后一个执行,这应该是官方经过了很多的测试选择的最佳方案吧。
3.6 Pointcut
- 这个就是将我们的切入点表达式起一个别名。
四、Spring继承MyBatis
4.1 xml的配置
- 首先我们需要在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.properties --> <context:property-placeholder location="jdbc.properties"/> <!-- 创建数据源--> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${jdbc.driverClassName}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <!-- 配置SqlSessionFactoryBean类 --> <bean class="org.mybatis.spring.SqlSessionFactoryBean"> <!-- 配置数据源--> <property name="dataSource" ref="dataSource"/> <!-- 配置MyBatis核心配置文件--> <property name="configLocation" value="SqlMapConfig.xml"/> <!-- 注册实体类的别名--> <property name="typeAliasesPackage" value="com.meteor.pojo"/> </bean> <!-- 注册mapper.xml文件--> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.meteor.mapper"/> </bean> </beans>
- 配置事务处理
使用 @Transactional(propagation=) <!-- 事务处理 --> <!-- 1.添加事务管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!-- 因为事务必须关联数据库处理,所以要配置数据源 --> <property name="dataSource" ref="dataSource"/> </bean> <!-- 添加事务的注解驱动 --> <tx:annotation-driven transaction-manager="transactionManager"/>
-
JDBC:Connection conn.commit(); conn.rollback();
-
MyBatis:SqlSession sqlSession.commit(); sqlSession.rollback();
-
Hibernate:Session session.commit(); session.rollback();
-
事务管理器用来生成相应技术的连接 + 执行语句的对象
-
如果使用MyBatis框架,必须使用DataSourceTransactionManager类完成处理
-
MySQL:mysql默认的事务处理级别是'REPEATABLE-READ',也就是可重复读
4.2 Spring事务传播特性
-
多个事务之间的合并、互斥等都可以通过设置事务的传播特性来解决
-
PROPAGATION_REQUIRED:必被包含事务(增删改必用)
-
PROPAGATION_REQUIRED_NEW:自己新开事务,不管之前是否有事务
-
PROPAGATION_SUPPORTS:支持事务,如果加入的方法有事务,则支持事务,如果没有,不单开事务
-
PROPAGATION_NEVER:不能运行中事务中,如果包在事务中,抛异常
-
PROPAGATION_NOT_SUPPORTED:不支持事务,运行在非事务的环境
-
项目中的所有事务,必须添加到业务逻辑层上。
五、结尾
- 这些只是Spring的基础入门知识,毕竟笔者也仅仅二刷,待笔者闭关修炼,后续会继续更新源码底层知识。
- 对于Spring内容就总结这么多,若想深入学习等待后续更新。
- 我将会继续更新关于Java方向的学习知识,感兴趣的小伙伴可以关注一下。
- 文章写得比较走心,用了很长时间,绝对不是copy过来的!
- 尊重每一位学习知识的人,同时也尊重每一位分享知识的人。
- 你的点赞与关注,是我努力前行的无限动力。