使用aop:目的是给已经存在的一些类和方法,增加额外的功能。前提是不改变原来类的代码
使用aspectj实现aop的基本步骤:
1.新建maven项目
2.加入依赖
1)spring依赖
2)aspectj依赖
3)junit单元测试
加入依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.3.5</version>
</dependency>
3.创建目标类
接口和他的实现类。
要做的是给类中的方法增加功能
4.创建切面类
普通类
1)在类的上面加入@Aspect
2)在类中定义方法,方法就是切面要执行的功能代码
在方法的上面加入aspectj中的通知注解,
例如@Before
有需要指定切入点表达式exection()
5.创建spring的配置文件
声明对象,把对象交给容器统一管理。
声明对象你可以使用注解或者xml配置文件bean
1)声明目标对象
2)声明切面类对象
3)声明aspectj矿建中的自动代理生成器标签
自动代理生成器:用来完成代理对象的自动创建功能的。
6.创建测试类
从spring容器中获取目标对象(实际就是代理对象)。
通过代理执行方法,实现aop的功能增强。
[掌握]@Before前置通知-方法有JoinPoint参数
在目标方法执行之前执行。被注解为前置通知的方法。可以包含一个JoinPoint类型参数。该类型的对象本身就是切入点表达式。通过该参数。可获取切入点表达式、方法签名、目标对象等。
不光前置通知的方法。可以包含一个JoinPoint类型参数,所有的通知方法均可包含该参数。
在方法之后自动执行的通知称为后置通知,可以应用于关闭流、上传文件、删除临时文件等功能。
连接点指可以被切面织入的具体方法,通常业务接口中的方法均为连接点
<!-- 把对象交给spring容器 ,有spring容器统一创建,管理对象 -->
<!-- 声明目标对象 -->
<bean id="someService" class="com.sdyu.ch06.SomeServiceImpl"/>
<!-- 声明切面类对象 -->
<bean id="myAspect" class="com.sdyu.ch06.MyAspect"/>
<!-- 声明自动代理生成器 使用aspectj框架内部的功能,创建目标对象的代理对象。
创建代理对象是在内存中实现的,修改目标对象的内存中的结构,创建为代理对象,
所以目标对象就是被修改后的代理对象
aspectj-autoproxy:会把spring容器中的所有目标都对象,一次性都生成代理对象。
-->
<aop:aspectj-autoproxy />
/**
* @Aspect:是aspect框架中的注解。
*
* 作用:表示当前类是切面类
* 切面类:是用来给业务方法增加功能的类,在这个类中有切面的功能代码
* 位置:在类定义的上面
*/
@Aspect
public class MyAspect {
/**
* 定义方法,方法是实现切面功能的
* 方法定义的要求:
* 1.公共方法public
* 2.方法没有返回值
* 3.方法名称自定义
* 4.方法可以有参数,也可以没有参数
* 如果有参数,参数不是自定义的,有几个参数类型可以使用。
*
*
*/
/**
* @Before:前置通知注解
* 属性:value,是切入点表达式,表示切面的功能执行的位置。
* 位置:在方法的上面
*
* 特点:
* 1.在目标方法之前先执行的
* 2.不会改变目标方法的执行结果
* 3.不会影响目标方法的执行
*/
@Before(value = "execution(public void com.sdyu.ch06.SomeServiceImpl.doSome(String,Integer))")
public void myBefore() {
//就是你切面要执行的功能代码
System.out.println("前置通知,切面功能:在目标方法之前输出执行时间:"+ new Date());
}
}
```java
package com.sdyu.ch06;
public interface SomeService {
void doSome(String name, Integer age);
}
package com.sdyu.ch06;
public class SomeServiceImpl implements SomeService {
@Override
public void doSome( String name,Integer age) {
//给doSome方法增加一个功能,在doSome()执行之前,输出方法的执行时间
System.out.println("=====目标方法doSome()=====");
}
}
JoinPoint参数使用
- 指定通知方法中的参数:JoinPoint
- JoinPoint :业务方法,要加入切面功能的业务方法
- 作用是:可以在通知方法中获取方法执行时的信息,例如方法名称,方法的实参。
- 如果你的切面功能中需要用到方法的信息,就加入JoinPoint
- 这个JoinPoint 参数的值是由框架赋予,必须是第一个位置的参数
- public void MyAfterReturning(JoinPoint jp,Object res) {//JoinPoint要在第一个参数
@Before(value = "execution(* com.sdyu.ch06.SomeServiceImpl.doSome(..))")
public void myBefore(JoinPoint jp) {
//就是你切面要执行的功能代码
System.out.println("前置通知,切面功能:在目标方法之前输出执行时间:"+ new Date());
//获取方法的完整定义
System.out.println("方法的签名(定义):"+jp.getSignature());
System.out.println("方法的名称"+jp.getSignature().getName());
Object args [] =jp.getArgs();
for(Object i :args) {
System.out.println("参数="+i);
}
}
### [掌握]@AfterReturn后置通知-注解有returning属性
@Aspect
public class MyAspect {
/**
* 后置通知定义方法,方法是实现切面功能的
* 方法定义的要求:
* 1.公共方法public
* 2.方法没有返回值
* 3.方法名称自定义
* 4.方法可以有参数,也可以没有参数
* 如果有参数,参数不是自定义的,有几个参数类型可以使用。
/
/*
* @AfterReturning:后置通知
* 属性:1.value切入点表达式
* 2.returning 自定义的变量,表示目标方法的返回值的。
* 自定义变量名必须和通知方法的形参名一样。
* 位置:在方法定义的上面
* 1。在目标方法之后执行的。
* 2.能够获取到目标方法的返回值,可以根据这个返回值做不同的处理功能
* 3.可以修改这个返回值
*
* 后置通知的执行
* Object res = doOther();
* myAfterReturning(res);
* 参数传递:传值,传引用
* System.out.println(“res”+res)
// */
// @AfterReturning(value = "execution(* *..SomeServiceImpl.doOther(..))",returning = "res")
// public void MyAfterReturning(Object res) {
// //Object res:是目标方法执行后的返回值,根据返回值做你的切面的功能处理
// System.out.println("后置通知,在目标方法之后执行的,获取的返回值是:"+res);
// if(res.equals("abcd")) {
// //做一些功能
// }else {
// //做一些功能
// }
//
// //修改目标方法的返回子 ,看一下是否会影响 最后的发给发调用结果
// if(res != null) {
// res = "hello";
// }
// }
@Override
public Student doOther2(String name, Integer age) {
Student student = new Student();
student.setName("大");
student.setAge(23);
return null;
}
[掌握]@Around环绕通知-增强方法有ProceedingJoinPoint参数
/**
* 环绕通知方法的定义格式
* 1.public
* 2.必须要有一个返回值
* 3.方法名称自定义
* 4.方法有参数,固定的参数 ProceedingJoinPoint
*/
/**
* @throws Throwable
* @Around:环绕通知
* 属性:value切入点表达式
* 位置:在方法的定义什么
* 特点:
* 1.他是功能最强的通知
* 2.在目标方法的前和后都能增强功能。
* 3.控制目标方法是否被调用执行
* 4.修改原来的目标方法的执行结果。影响最后的调用结果
*
*
* 环绕通知,等于jdk动态代理,InovactionHandler接口
*
* 参数:ProceedingJoinPoint 就等同于Method
* 作用:执行目标方法的
* 返回值:就是目标方法的执行结果,可以被修改。
*
* 环绕通知:经常做实物,在目标方法之前开启事务,执行目标方法,在目标方法
* 之后提交事务
*/
```java
@Around(value = "execution(* *..SomeService.doFirst(..))")
public Object myAround(ProceedingJoinPoint pjp) throws Throwable {
String name ="";
//获取第一个参数值
Object args[] =pjp.getArgs();
if(args != null && args.length > 1) {
Object arg = args[0];
name=(String)arg;
}
//实现环绕通知
Object result =null;
System.out.println("环绕通知:在目标方法之前,输出事件:"+new Date());
if("zhangsan".equals(name)) {
//符合条件,调用目标方法
//1.目标方法调用
result = pjp.proceed();//method.invoke();
}
System.out.println("环绕通知:在目标方法之后,输出事件:"+result+new Date());
//2.在目标方法的前或者后,加入功能
//修改目标的执行结果,影响方法执行时,增强了功能
if(result != null) {
result = "Hello Aspect AOP";
}
//返回目标方法的执行结果
return result;
}
[了解]@AfterThrowing异常通知-注解中有throwing属性
import java.util.Date;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class MyAspect {
/**
* 异常通知方法的定义格式
* 方法定义的要求:
* 1.公共方法public
* 2.方法没有返回值
* 3.方法名称自定义
* 4.方法有个Exception,如果有是JoinPoint
*/
/**
* @AfterThrowing:异常通知
* 属性:1.value 切入点表达式
* 2.throwing 自定义的变量,表示目标方法抛出的异常对象。
* 变量名必须和方法的参数名一样
* 特点:
* 1.在目标方法抛出异常时执行的
* 2.可以做异常的监控程序,监控目标方法执行时是不是有异常。
* 如果有异常,可以发送邮件,短信进行通知
*
* 执行就是:
* try{
* SomeServiceImpl.doSecond(..)
* }catch(Exception e){
* myAfterThrowing(e);
* }
*/
@AfterThrowing(value="execution(* *..SomeServiceImpl.doSecond(..))",throwing ="e")
public void myAfterThrowing(Exception e) {
System.out.println("异常通知:方法发生异常,执行:"+e.getMessage());
//发送邮件,短信,通知开发人员
}
}
public class MyTest2 {
@Test
public void test01() {
String config="applicationContext.xml";
ApplicationContext acx = new ClassPathXmlApplicationContext(config);
SomeService sd = (SomeService) acx.getBean("someService");
sd.doSecond();
}
}
[了解]@After最终通知
@Aspect
public class MyAspect {
/**
* 异常通知方法的定义格式
* 方法定义的要求:
* 1.公共方法public
* 2.方法没有返回值
* 3.方法名称自定义
* 4.无参数,如果有还是JoinPoint,
*/
/**
* @After:最终通知
* 属性:value 切入点表达式
*
* 位置:在方法的上面
*
* 特点:
* 1.总是会执行
* 2.在目标方法之后执行的
*
*/
@After(value="execution(* *..SomeServiceImpl.doThird(..))")
public void myAfter() {
System.out.println("执行最终通知,");//有异常也会被执行
}
}
public class MyTest2 {
@Test
public void test01() {
String config="applicationContext.xml";
ApplicationContext acx = new ClassPathXmlApplicationContext(config);
SomeService sd = (SomeService) acx.getBean("someService");
sd.doThird();
}
}
@Pointcut定义切入点(辅助)
@Aspect
public class MyAspect {
/**
* 异常通知方法的定义格式
* 方法定义的要求:
* 1.公共方法public
* 2.方法没有返回值
* 3.方法名称自定义
* 4.无参数,如果有还是JoinPoint,
*/
/**
* @After:最终通知
* 属性:value 切入点表达式
*
* 位置:在方法的上面
*
* 特点:
* 1.总是会执行
* 2.在目标方法之后执行的
*
*/
@After(value="mypt()")
public void myAfter() {
System.out.println("执行最终通知,方法之后执行");
}
@Before(value="mypt()")
public void myBefore() {
System.out.println("执行前置通知,方法之前执行");
}
/**
* @Pointcut:定义和管理切入点表达式,如果你的项目中有多少个切入点表达式是重复的,可以复用的。
* 可以使用@Pointcut
* 属性:value 切入点表达式
* 位置:在自定义的方法上面
* 特点:
* 当使用@Pointcut定义在一个方法的上面,此时这个方法的名称就是切入点表达式的别名,、
* 其他的通知中,value属性就可以使用这个方法名称,代替切入点表达式了
*/
@Pointcut(value="execution(* *..SomeServiceImpl.doThird(..))" )
private void mypt() {
//无需代码,
}
}
public class MyTest2 {
@Test
public void test01() {
String config="applicationContext.xml";
ApplicationContext acx = new ClassPathXmlApplicationContext(config);
SomeService sd = (SomeService) acx.getBean("someService");
sd.doThird();
}
}
如果有接口使用cglib
<!--
如果你期望目标类有接口,使用cglib代理
proxy-target-class="true" :告诉框架,要用cglib代理
-->
<aop:aspectj-autoproxy proxy-target-class="true"/>
Spring整合Mybatis集成
用的技术是:IOC
为什么IOC:能把mybatis和spring集成在一起,像一个框架,因为IOC可以创建框架
可以把Mybatis框架中的对象交给spring统一,开发人员从spring中获取对象。
开发人员不用同时面对两个或多个框架了,就面对一个spring
mybatis使用步骤,对象
1.定义dao接口,StudentDao
2.定义mapper文件StudentDao.xml
3.定义mybatis的主配置文件mybatis.xml
4.创建dao的代理对象,SqlSession.getMapper(StudentDao.class);
List students = dao.selectStudents();
要使用dao对象,需要使用getMapper()方法,
怎么能使用getMapper()方法,需要哪些条件
1.获取SqlSession对象 ,需要使用SqlSessionFactory的openSession()方法
2.创建SqlSessionFactory对象。使用Factory能获取SqlSession,有了SqlSession能有dao,目的就是获取dao对象
Factory创建需要读取主配置文件
我们会使用独立的连接池替换mybatis默认自己带的,把连接池类也交给spring来创建。
主配置文件
1.数据库信息
<environments default="online">
<!--唯一值 id -->
<environment id="mydev">
<!-- 数据源 -->
<transactionManager type="JDBC"/>
<!-- 连接池 -->
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/student?serverTimezone=UTC&&characterEncoding=utf-8
jdbc.user=root
jdbc.password=123456
2.mapper文件位置
<mappers>
<mapper resource="com/sdyu/dao/StudentDao.xml"/>
</mappers>
=========================================================================================================
通过以上说明,我们需要让spring创建以下对象
1.独立的连接池类的对象,使用阿里的druid连接池
2.SqlSessionFactory对象
3.创建dao对象
需要学习就是上面三个对象的创建语法,使用xml的bean标签。(目前)
总体依赖:
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!-- spring核心 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.5</version>
</dependency>
<!-- spring做事务的 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.3.5</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.5</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<!-- mybatis和spring集成依赖 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.22</version>
</dependency>
<!-- 阿里数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.5</version>
</dependency>
插件:
<build>
<resources>
<resource>
<directory>src/main/java</directory><!-- 所在的目录 -->
<includes>
<!-- 包括目录下的.properties.xml 文件都会扫描 -->
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<sorce>1.8</sorce>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
以后常用mybatis模板
<?xml version="1.0" encoding="UTF-8"?><?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>
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<!-- 设置别名 -->
<typeAliases>
<!-- name:实体类所在的包名 -->
<package name="com.sdyu.entity"/>
</typeAliases>
<mappers>
<!-- name:是包名,这个包中所有的mapper.xml 一次性加载
-->
<package name="com.sdyu.dao"/>
</mappers>
</configuration>
application.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:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://mybatis.org/schema/mybatis-spring
http://mybatis.org/schema/mybatis-spring-1.2.xsd">
<!-- 声明数据源DataSource,作用是连接数据库 -->
<bean id="mydataSource" class="com.alibaba.druid.pool.DruidDataSource"
init-method="init"
destroy-method="close">
<!-- 使用set注入给DruidDataSrouce提供连接数据库信息 -->
<property name="url" value="jdbc:mysql://localhost:3306/student?serverTimezone=UTC& characterEncoding=utf-8" />
<property name="username" value="root" />
<property name="password" value="123456" />
<property name="maxActive" value="20" />
</bean>
<!-- 声明的是mubatis中提供的SqlSessionFactoryBean类,这个类内部创建SqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- set注入,把数据连接池赋给了dataSource -->
<property name="dataSource" ref="mydataSource"/>
<!-- mybatis主配置文件
configLocationResource属性是Resource类型,读取配置文件
他的赋值,使用value,指定文件的路径,使用classpath:表示文件的位置
-->
<property name="configLocation" value="classpath:Mybatis.xml"/>
</bean>
</beans>
jdbc.properties
jdbc.url=jdbc:mysql://localhost:3306/student?serverTimezone=UTC&&characterEncoding=utf-8
jdbc.username=root
jdbc.password=123456
jdbc.maxActive=20