1、AOP

1.1、什么是AOP

AOP(Aspect Oriented Programming),意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP(面向对象编程)的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

1.2 AOP在Spring中的作用

提供声明式事务;允许用户自定义切面

  • 横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如日志,安全,缓存,事务等等…
  • 切面(ASPECT):横切关注点被模块化的特殊对象。即,它是一个类。
  • 通知(Advice):切面必须要完成的工作。即,它是类中的一个方法。
  • 目标(Target):被通知对象。
  • 代理(Proxy):向目标对象应用通知之后创建的对象。
  • 切入点(PointCut):切面通知执行的“地点”的定义。
  • 连接点(JointPoint):与切入点匹配的执行点。

即 Aop在 不改变原有代码的情况下,去添加新的功能

1.3、使用Spring实现Aop

【重点】使用AOP织入,需要导入一个依赖包

  1. <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
  2. <dependency>
  3. <groupId>org.aspectj</groupId>
  4. <artifactId>aspectjweaver</artifactId>
  5. <version>1.9.4</version>
  6. </dependency>

准备工作

  1. 接口和实现接口的实现类

    1. public interface UserService {
    2. public void add();
    3. public void delete();
    4. public void update();
    5. public void select();
    6. }
  1. 方式一:使用Spring的API接口【主要SpringAPI接口实现】

    1. Log ```java public class Log implements MethodBeforeAdvice {

    // method: 要执行的目标对象的方法 // args: 参数 // target: 目标对象

    public void before(Method method, Object[] args, Object target) throws Throwable {

    1. System.out.println(target.getClass()+"的"+method.getName()+"执行了");

    } } ```

  1. AfterLog

    1. public class AfterLog implements AfterReturningAdvice {
    2. // returnValue : 返回值
    3. public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
    4. System.out.println("执行了"+method.getName()+"方法,返回结果为:"+returnValue);
    5. }
    6. }
  1. 编写AOP ```xml
  1. <aop:config>
  2. <!--切入点:expression:表达式,execution(* com.shuai.service.UserServiceImpl.*(..))-->
  3. <aop:pointcut id="pointcut" expression="execution(* com.shuai.service.UserServiceImpl.*(..))"/>
  4. <!--执行环绕添加-->
  5. <aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
  6. <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
  7. </aop:config>
  1. 3. 方式二:自定义来实现AOP【主要是切面定义】
  2. 1. 编写一个类
  3. ```java
  4. public class DiyPointCut {
  5. public void before(){
  6. System.out.println("========方法执行前==========");
  7. }
  8. public void after(){
  9. System.out.println("========方法执行后==========");
  10. }
  11. }
  1. 编写AOP ```xml
  1. <bean id="diy" class="com.shuai.diy.DiyPointCut"/>
  2. <aop:config>
  3. <aop:aspect ref="diy">
  4. <aop:pointcut id="point" expression="execution(* com.shuai.service.UserServiceImpl.*(..))"/>
  5. <aop:before method="before" pointcut-ref="point"/>
  6. <aop:after method="after" pointcut-ref="point"/>
  7. </aop:aspect>
  8. </aop:config>
  1. 4. 方式三:使用注解实现!
  2. 1. 编写一个类
  3. ```java
  4. // 方式三:使用注解方式实现AOP
  5. @Aspect // 标注这个类是一个切面
  6. public class AnnotationPointCut {
  7. @Before("execution(* com.shuai.service.UserServiceImpl.*(..))")
  8. public void before(){
  9. System.out.println("======方法执行前=======");
  10. }
  11. @After("execution(* com.shuai.service.UserServiceImpl.*(..))")
  12. public void after(){
  13. System.out.println("========方法执行后========");
  14. }
  15. @Around("execution(* com.shuai.service.UserServiceImpl.*(..))")
  16. public void around(ProceedingJoinPoint jp) throws Throwable {
  17. System.out.println("环绕前");
  18. Signature signature = jp.getSignature(); // 获得签名
  19. System.out.println("signature:"+ signature);
  20. Object proceed = jp.proceed(); // 执行方法
  21. System.out.println("环绕后");
  22. System.out.println(proceed);
  23. }
  24. }
  1. 编写AOP ```xml
<a name="cb426fda"></a> ## 2、整合Mybatis 步骤: 1. 导入相关jar包 - junit - mybatis - mysql数据库 - spring相关 - aop织入器 - mybatis-spring整合包【重点】在此还导入了lombok包。 - 配置Maven静态资源过滤问题! 2. 编写配置文件 2. 测试 <a name="1bcd7f27"></a> ### 2.1、回忆mybatis 1. 编写实体类 1. 编写核心配置文件 1. 编写接口 1. 编写Mapper.xml 1. 测试 <a name="718cacaa"></a> ### 2.2、Mybatis-spring 1. 编写实体类java public class User { private int id; private String name; private String pwd; } 2. 编写dao层接口java public interface UserMapper { List selectUser(); } 3. 编写核心配置文件xml <?xml version=”1.0” encoding=”UTF-8” ?> <!DOCTYPE configuration PUBLIC “-//mybatis.org//DTD Config 3.0//EN” “http://mybatis.org/dtd/mybatis-3-config.dtd"> 4. 编写UserMapper.xmlxml <?xml version=”1.0” encoding=”UTF-8” ?> <!DOCTYPE mapper PUBLIC “-//mybatis.org//DTD Mapper 3.0//EN” “http://mybatis.org/dtd/mybatis-3-mapper.dtd"> insert into user (id,name,pwd) values (#{id},#{name},#{pwd}) deletes from user where id=#{id} 5. 引入spring-dao.xmlxml
  1. <!--sqlSessionFactory-->
  2. <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
  3. <property name="dataSource" ref="dataSource"/>
  4. <!--绑定Mybatis配置文件-->
  5. <property name="configLocation" value="classpath:mybatis-config.xml"/>
  6. <property name="mapperLocations" value="classpath:com/shuai/dao/UserMapper.xml"/>
  7. </bean>
  8. <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
  9. <constructor-arg index="0" ref="sqlSessionFactory"/>
  10. </bean>
  11. <bean id="userMapper" class="com.shuai.dao.UserMapperImpl">
  12. <property name="sqlSession" ref="sqlSession"/>
  13. </bean>
  1. 6. 编写实体类
  2. 1. 方式一(UserMapperImpl)
  3. ```java
  4. public class UserMapperImpl implements UserMapper{
  5. // 我们的所有操作,都是用sqlSession来执行,在原来,现在都是用SqlSessionTemplate;
  6. private SqlSessionTemplate sqlSession;
  7. public void setSqlSession(SqlSessionTemplate sqlSession) {
  8. this.sqlSession = sqlSession;
  9. }
  10. public List<User> selectUser() {
  11. return sqlSession.getMapper(UserMapper.class).selectUser();
  12. }
  13. }
  1. 方式二(UserMapperImpl2)

    1. public class UserMapperImpl2 extends SqlSessionDaoSupport implements UserMapper{
    2. public List<User> selectUser() {
    3. return getSqlSession().getMapper(UserMapper.class).selectUser();
    4. }
    5. }
  1. 引入applicationContext.xml(测试UserMapperImpl2) ```xml
8. 测试java public class MyTest { @Test public void getUser() throws IOException { ApplicationContext context = new ClassPathXmlApplicationContext(“spring-dao.xml”); UserMapper userMapper = context.getBean(“userMapper”, UserMapper.class); List users = userMapper.selectUser(); for (User user : users) { System.out.println(user); } } } <a name="982baa3c"></a> ## 3、声明式事务 <a name="b925bf0c"></a> ### 3.1、回顾事务 - 把一组业务当成一个业务来做;要么都成功,要么都失败! - 事务在项目开发中,十分的重要,涉及到数据的一致性问题,不能马虎! - 确保完整性和一致性。 事务ACID原则: - 原子性(atomicity) - 事务是原子性操作,由一系列动作组成,事务的原子性确保动作要么全部完成,要么完全不起作用。 - 一致性(consistency) - 一旦所有事务动作完成,事务就要被提交。数据和资源处于一种满足业务规则的一致性状态中。 - 隔离性(isolation) - 可能多个事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏。 - 持久性(durability) - 事务一旦完成,无论系统发生什么错误,结果都不会受到影响。通常情况下,事务的结果被写到持久化存储器中。 <a name="ec18b5b4"></a> ### 3.2、spring中的事务管理 Spring在不同的事务管理API之上定义了一个抽象层,使得开发人员不必了解底层的事务管理API就可以使用Spring的事务管理机制。Spring支持编程式事务管理和声明式的事务管理。 **编程式事务管理** - 将事务管理代码嵌到业务方法中来控制事务的提交和回滚 - 缺点:必须在每个事务操作业务逻辑中包含额外的事务管理代码 **声明式事务管理**(AOP) - 一般情况下比编程式事务好用。 - 将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。 - 将事务管理作为横切关注点,通过aop方法模块化。Spring中通过Spring AOP框架支持声明式事务管理。 测试步骤: 1. 引入上面spring与mybatis的整合 1. 在spring-dao.xml中引入声明式事务xml

  1. 3. 编写实体类(UserMapperImpl
  2. ```java
  3. public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper{
  4. public List<User> selectUser() {
  5. User user = new User(5, "少帅", "123456");
  6. UserMapper mapper = getSqlSession().getMapper(UserMapper.class);
  7. mapper.addUser(user);
  8. mapper.deleteUser(3);
  9. return mapper.selectUser();
  10. }
  11. public int addUser(User user) {
  12. return getSqlSession().getMapper(UserMapper.class).addUser(user);
  13. }
  14. public int deleteUser(int id) {
  15. return getSqlSession().getMapper(UserMapper.class).deleteUser(id);
  16. }
  17. }
  1. 测试

思考:

为什么需要事务?

  • 如果不配置事务,可能存在数据提交不一致的情况
  • 如果我们不在spring中去配置声明式事务,我们就需要在代码中手动配置事务
  • 事务在项目的开发中十分重要,设计到数据的一致性和完整性问题!