Spring-AOP及集成mybatis和jdbcTemplate

1 AOP

1.1 AOP的介绍

使用面向对象编程 ( OOP )有一些弊端,当需要为多个不具有继承关系的对象引人同一个公共行为时,例如日志、安全检测等,我们只有在每个对象里引用公共行为,这样程序中就产生了大量的重复代码,程序就不便于维护了,所以就有了一个对面向对象编程的补充,即面向方面编程 ( AOP ), AOP 所关注的方向是横向的,区别于 OOP 的纵向。

1.2 AOP的作用

在不修改源码的情况下,对程序进行增强
AOP 可以进行权限校验,日志记录,性能监控,事务控制

1.3 AOP的底层实现

AOP依赖于IOC来实现,在AOP中,使用一个代理类来包装目标类,在代理类中拦截目标类的方法执行并织入辅助功能。

代理机制:
Spring 的 AOP 的底层用到两种代理机制:
JDK 的动态代理 :针对实现了接口的类产生代理.
Cglib 的动态代理 :针对没有实现接口的类产生代理. 应用的是底层的字节码增强的技术 生成当前类的子类对象.

1.4 动态代理

Java中提供的动态代理,增强一个类的方法

package com.tledu.service.impl;

import lombok.Getter;
import lombok.Setter;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * @author cyrus
 */
public class LogInterceptor implements InvocationHandler {
    /**
     * 被代理的对象
     */
    @Getter
    @Setter
    private Object target;

    private void before(Method method) {
        System.out.println(method.getName()+"调用之前");
    }

    private void after(Method method) {
        System.out.println(method.getName()+"调用之后");
    }

    /**
     * @param proxy  代理的对象
     * @param method 代理的方法
     * @param args   方法的参数
     * @return 方法的返回值
     * @throws Throwable 异常
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 前置操作
        before(method);
        // 通过被代理对象调用真正需要执行的方法
        Object res = method.invoke(target, args);
        // 后置操作
        after(method);
        return res;
    }
}

测试

    @Test
    public void proxy() {
        // 创建真实的对象
        IUserDao userDao = new UserDaoImpl();
        // 创建代理
        LogInterceptor logInterceptor = new LogInterceptor();
        // 设置需要代理的对象
        logInterceptor.setTarget(userDao);
        // 创建代理之后的对象
        /*
          第一个参数: 真实对象的类解析器
          第二个参数: 实现的接口数组
          第三个参数: 调用代理方法的时候,会将方法分配给该参数
         */
        IUserDao userDaoProxy = (IUserDao) Proxy.newProxyInstance(userDao.getClass().getClassLoader(),
                new Class[]{IUserDao.class}, logInterceptor);
        userDaoProxy.insert(null);
    }

1.5 AOP相关术语

Joinpoint(连接点): 所谓连接点是指那些被拦截到的点。在 spring 中,这些点指的是方法,因为 spring 只支持方法类型的连接点.

Advice(通知/增强): 所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知.通知分为前置通知,后置 通知,异常通知,最终通知,环绕通知(切面要完成的功能)

Pointcut(切入点): 所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义

Introduction(引介): 引介是一种特殊的通知在不修改类代码的前提下, Introduction 可以在运行期为类 动态地添加一些方法或 Field.

Target(目标对象): 代理的目标对象

Weaving(织入): 是指把增强应用到目标对象来创建新的代理对象的过程,spring 采用动态代理织入,而 AspectJ 采用编译期织入和类装在期织入

Proxy(代理): 一个类被 AOP 织入增强后,就产生一个结果代理类

Aspect(切面): 是切入点和通知(引介)的结合

1.6 实现方法

1.6.1 注解实现

1.6.1.1 引入依赖
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>${spring.version}</version>
</dependency>
<!-- 增加了切面 -->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.5</version>
</dependency>
1.6.1.2 加上注解

在需要实现的类上加注解

@EnableAspectJAutoProxy
public class SpringConfiguration {
}
1.6.1.3 编写AOP类
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Component
@Aspect
public class LogInterceptor {
	@Pointcut("execution(public * com.tledu.spring.service..*.add(..))")
	public void myMethod() {
  // 假设这个方法就是被代理的方法
	}
	@Before("myMethod()")
	public void beforeMethod() {
  System.out.println(" execute start");
	}
	@After("myMethod()")
	public void afterMethod() {
  System.out.println(" execute end");
	}
	// 环绕,之前和之后都有,相当于 @Before 和 @After 一起使用
	@Around("myMethod()")
	public void aroundMethod(ProceedingJoinPoint pjp) throws Throwable {
  // @Around也可以和@Before 和 @After 一起使用
  System.out.println("around start");
  // 调用被代理的方法
  pjp.proceed();
  System.out.println("around end");
	}
}

1.6.2 xml实现

1.6.2.1 引入依赖
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>${spring.version}</version>
</dependency>
<!-- 增加了切面 -->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.5</version>
</dependency>
1.6.2.2 配置xml文件
<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: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
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<!-- 实例化 -->
	<bean id="logInterceptroe" class="com.tledu.spring.aop.LogInterceptor"></bean>
	<!-- 设置AOP -->
	<aop:config>
  <aop:aspect id="logAspect" ref="logInterceptroe">
  	<!-- 需要进行代理的方法 -->
  	<aop:pointcut expression="execution(public * com.tledu.spring.service..*.add(..))"
    id="pointcut" />
  	<!-- 前后执行 -->
  	<aop:before method="before" pointcut-ref="pointcut" />
  	<!-- 或者这样写,这样就不需要pointcut标签了 -->
  	<!-- <aop:before method="before" pointcut="execution(public * com.tledu.spring.service..*.add(..))"  
    /> -->
  	<aop:after method="after" pointcut-ref="pointcut" />
  	<!-- 环绕,一般要么使用 around 要和使用 before和after 不会一起使用 -->
  	<aop:around method="aroundMethod" pointcut-ref="pointcut" />
  </aop:aspect>
</aop:config>
1.6.2.3 编写AOP类
//和注解一样,就是把注解去掉了
import org.aspectj.lang.ProceedingJoinPoint;
public class LogInterceptor {
	public void myMethod() {
  // 假设这个方法就是被代理的方法
	}
	public void before() {
  System.out.println(" execute start");
	}
	public void after() {
  System.out.println(" execute end");
	}
	// 环绕,之前和之后都有,相当于 @Before 和 @After 一起使用
	public void aroundMethod(ProceedingJoinPoint pjp) throws Throwable {
  // @Around也可以和@Before 和 @After 一起使用
  System.out.println("around start");
  // 调用被代理的方法
  pjp.proceed();
  System.out.println("around end");
}
}

1.7 AOP实现记录操作日志

1.7.1 自定义一个注解

@Retention(RetentionPolicy.RUNTIME)
public @interface Log {
    //操作类型
    String type() default "";
    //具体描述
    String desc() default "";
}

1.7.2 编写一个切面类

@Aspect
@Component
public class LogAspect {
    @Before("@annotation(com.tledu.spring05.logger.Log)")
    public void before(JoinPoint joinPoint) {
        //获取到接口的实现类
        Class clazz = joinPoint.getTarget().getClass();
        //获取方法名
        String methodName = joinPoint.getSignature().getName();
        //获取参数列表
        Class[] classes = ((MethodSignature) joinPoint.getSignature()).getMethod().getParameterTypes();
        try {
            //获取方法
            Method method = clazz.getMethod(methodName, classes);
            //获取方法上的注解
            Log log = method.getAnnotation(Log.class);
            System.out.println(log.desc());
            System.out.println(log.type());
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

    }
}

2 Spring集成Mybatis

2.1 引入依赖

<!--引入相关依赖-->
<!-- spring jdbc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>${spring.version}</version>
</dependency>
<!-- mybatis-->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.4.5</version>
</dependency>
<!-- 与spring整合 -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>1.3.1</version>
</dependency>
<!-- 数据库驱动 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.12</version>
</dependency>
<!-- 连接池 -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.7</version>
</dependency>

2.2 添加mybatis的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">
<configuration>
    <typeAliases>
        <!--几十个实体类-->
        <!--<typeAlias type="com.tledu.spring.model.User" alias="User"/>-->
        <package name="com.tledu.spring.model"/>
    </typeAliases>
    <mappers>
        <package name="com.tledu.spring.mapper"/>
    </mappers>
</configuration>

2.3 添加数据库配置文件

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/erp16?useUnicode=true&characterEncoding=UTF-8
jdbc.username=root
jdbc.password=root
jdbc.max=50
jdbc.min=10

2.4 添加spring的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: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
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
    <!--配置扫描注解-->
    <context:annotation-config/>
    <!--告诉spring,要扫描com.tledu包下面的注解-->
    <context:component-scan base-package="com.tledu"/>
    <!--开启切面支持-->
    <aop:aspectj-autoproxy/>

    <!-- 1) 读取properties中的内容-->
    <context:property-placeholder location="classpath:jdbc.properties"/>

    <!-- 2) 数据库连接池 -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
        <property name="maxActive" value="${jdbc.max}"/>
        <property name="minIdle" value="${jdbc.min}"/>
    </bean>

    <!-- 3) 获取 SqlSessionFactory 工厂类-->
    <bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="configLocation" value="classpath:mybatis-config.xml" />
    </bean>

    <!-- 4) 搜索有哪些 mapper 实现类,把mapper接口自动配置成 spring 中的 <bean>-->
    <bean id="scannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!-- name="basePackage":(起始)包名, 从这个包开始扫描-->
        <property name="basePackage" value="com.tledu.mapper"/>
    </bean>

</beans>

2.5 添加日志的配置文件

### Log4j配置 ###
#定义log4j的输出级别和输出目的地(目的地可以自定义名称,和后面的对应)
#[ level ] , appenderName1 , appenderName2
log4j.rootLogger=DEBUG,console,file
#-----------------------------------#
#1 定义日志输出目的地为控制台
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold=DEBUG
####可以灵活地指定日志输出格式,下面一行是指定具体的格式 ###
#%c: 输出日志信息所属的类目,通常就是所在类的全名
#%m: 输出代码中指定的消息,产生的日志具体信息
#%n: 输出一个回车换行符,Windows平台为"/r/n",Unix平台为"/n"输出日志信息换行
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n
#-----------------------------------#
#2 文件大小到达指定尺寸的时候产生一个新的文件
log4j.appender.file = org.apache.log4j.RollingFileAppender
#日志文件输出目录
log4j.appender.file.File=log/info.log
#定义文件最大大小
log4j.appender.file.MaxFileSize=10mb
###输出日志信息###
#最低级别
log4j.appender.file.Threshold=ERROR
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n
#-----------------------------------#
#3 druid
log4j.logger.druid.sql=INFO
log4j.logger.druid.sql.DataSource=info
log4j.logger.druid.sql.Connection=info
log4j.logger.druid.sql.Statement=info
log4j.logger.druid.sql.ResultSet=info
#4 mybatis 显示SQL语句部分
log4j.logger.org.mybatis=DEBUG
#log4j.logger.cn.tibet.cas.dao=DEBUG
#log4j.logger.org.mybatis.common.jdbc.SimpleDataSource=DEBUG
#log4j.logger.org.mybatis.common.jdbc.ScriptRunner=DEBUG
#log4j.logger.org.mybatis.sqlmap.engine.impl.SqlMapClientDelegate=DEBUG
#log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG

2.6 创建mapper

2.7 测试

3 事务

3.1 引入依赖

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-tx</artifactId>
    <version>${spring.version}</version>
</dependency>

3.2 在xml中添加配置

 <!-- 使使用注解配置的事务行为生效 -->
<tx:annotation-driven transaction-manager="txManager"/>
<!-- 仍然需要一个PlatformTransactionManager -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- (这个需要的对象是在其他地方定义的) -->
<property name="dataSource" ref="dataSource"/>
</bean>

3.3 直接使用注解

//rollbackFor:回滚的时机
//isolation:隔离级别
@Transactional(rollbackFor = Exception.class)
public int insert(User user) {
    // 根据数据做一些处理
    userDao2.insert(user);
    addressMapper.insert(new Address());
    throw new RuntimeException();
}

4 Spring中的JdbcTemplate

4.1 概述

它是 spring 框架中提供的一个对象,是对原始 Jdbc API 对象的简单封装

4.2 实现

4.2.1 引入依赖

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-jdbc</artifactId>
	<version>${spring.version}</version>
</dependency>

4.2.2 配置文件

<?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: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/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">

    <!--配置扫描注解-->
    <context:annotation-config/>
    <!--告诉spring,要扫描com.tledu包下面的注解-->
    <context:component-scan base-package="com.tledu"/>
    <!--加上aop的约束-->
    <aop:aspectj-autoproxy/>

    <context:property-placeholder location="classpath:jdbc.properties"/>
    <!-- 数据库连接池 -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
        <!--最大连接数-->
        <property name="maxActive" value="${jdbc.max}"/>
        <!--初始空闲池的个数-->
        <property name="minIdle" value="${jdbc.min}"/>
    </bean>
     <!-- 配置一个数据库的操作模板:JdbcTemplate -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource" />
    </bean>
</beans>

4.2.3 使用

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
 
/**
 * JdbcTemplate的最基本用法
 */
public class JdbcTemplateDemo2 {
 
    public static void main(String[] args) {
        //1.获取容器
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //2.获取对象
        JdbcTemplate jt = ac.getBean("jdbcTemplate",JdbcTemplate.class);
        //3.执行操作
        jt.execute("insert into account(name,money)values('ddd',2222)");
 
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值