AOP
概念:面向切面编程
作用:在不改动原代码的情况下对其功能进行增强
核心概念
连接点:所有正在运行的方法都是连接点(连接点包含切入点)
切入点:需要进行增强的连接点
切面:描述通知与切入点的对应关系
通知:增强的操作,也就是切入点需要进行增强的功能
通知类:通知方法所在的类
操作步骤
导入aop坐标,spring中会将aop传递过来
<!--spring核心依赖,会将spring-aop传递进来-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<!--切入点表达式依赖,目的是找到切入点方法,也就是找到要增强的方法-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
定义接口和实现类
public interface AopService {
void save();
}
@Service
public class AopServiceImpl implements AopService {
public void save() {
System.out.println("AopServiceImpl...");
}
}
定义aop通知类
@Component//通知类配置成配Spring管理的Bean
@Aspect//设置当前类为切面类
public class SpringAop {
@Pointcut("execution(void com.cyf.service.impl.AopServiceImpl.save())")//定义切入点
public void pt(){}
@Before("pt()")//将切入点和通知连接
public void method(){
System.out.println("SpringAop...");
}
}
定义配置类
@Configuration
@ComponentScan("com.cyf")
@EnableAspectJAutoProxy//开启aop
public class SpringConfig {
}
AOP的底层是动态代理
IOC容器中的对象,不再是原来的实现类对象,而是产生新的对象,在我们获取对象的时候,只能用接口类型
AOP通知类型
前置通知
在原代码执行前执行代码
@Before("pt()")//将切入点和通知连接
//前置通知,在执行原方法前执行
public void Before(){
System.out.println("SpringAop...Before");
}
后置通知
在源代码执行后执行代码
@After("pt()")
//后置通知,在执行原方法后执行
public void after(){
System.out.println("SpringAop...After");
}
环绕通知
增强的功能包裹原方法
/**
* //环绕通知,将增强的功能包裹原方法
* @param pjp 切入点的对象,通过对象执行切入点代码
* @return
* @throws Throwable
*/
@Around("pt()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("SpringAop...AroundBefore");
pjp.proceed();
System.out.println("SpringAop...AfterBefore");
return 200;
}
返回后通知
在正常运行后执行的方法
@AfterReturning("pt()")
//返回后通知,正常运行后执行的方法
public void afterreturning(){
System.out.println("SpringAop...AfterReturning");
}
抛出异常后通知
在抛出异常后执行
@AfterThrowing("pt()")
//抛出异常后通知,在出现异常后执行
public void afterthrowing(){
System.out.println("SpringAop...AfterThrowing");
}
数据获取
参数获取
除Around外,其他通知获取参数
@Before("pt()")
@After("pt()")
@AfterReturning("pt()")
@AfterThrowing("pt()")
public void Before(JoinPoint jp){
jp.getArgs(); //获取参数
}
Around通知获取参数
/**
* //环绕通知,将增强的功能包裹原方法
* @param pjp 切入点的对象,通过对象执行切入点代码
* @return
* @throws Throwable
*/
@Around("pt()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
pjp.getArgs();//获取参数
}
返回值获取
只有两个通知可以获取参数
Around获取参数
@Around("pt()")
public Object around(ProceedingJoinPoint pjp) throws Throwable { // 手动调用连接点方法,返回值就是连接点方法的返回值
Object ret = pjp.proceed();
return ret;
}
AfterReturning获取参数
@AfterReturning(value = "pt()",returning = "ret")
public void afterReturning(String ret) {
//变量名要和returning="ret"的属性值一致
System.out.println("afterReturning advice ..."+ret);
}
获取异常
AfterThrowing异常
@AfterThrowing(value = "pt()",throwing = "t")
public void afterThrowing(Throwable t) {
//变量名要和throwing = "t"的属性值一致
System.out.println("afterThrowing advice ..."+ t);
}
Around获取异常
@Around("pt()")
public Object around(ProceedingJoinPoint pjp) {
Object ret = null;
//此处需要try...catch处理,catch中捕获到的异常就是连接点方法中抛出的异常
try {
ret = pjp.proceed();
} catch (Throwable t) {
t.printStackTrace();
}
return ret;
}
instanceof比较
- instanceof关键字用来对比左边的对象是否属于右边的对象
- instanceof的左右两边必须是引用类型,java 八大基本数据类型无法使用 instanceof来进行对比
- instanceof用来判定左边的引用类型是否与右边的引用类型的类型是否相同,或左边引用类型是右边引用类型的子类或实现类(右边引用类型可以是类、抽象类、接口)
- null与任何引用类型进行 instanceof对比的结果都是 false,null不属于任何类型,更不属于 object基类的派生类(子类),需要特别注意
比较数据类型也可以用字节码进行对比,精确度100%
通过getClass的方法和String.class进行对比,比较数据类型
trim用于删除字符串头尾的空白符
Spring事务配置
步骤:
1.配置事务管理器
//配置事务管理器,mybatis使用的是jdbc事务
//需要在jdbc管理器中配置
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource){
return new DataSourceTransactionManager(dataSource);
}
2.开启注释事务驱动
@Configuration
@ComponentScan("com.cyf")
@PropertySource("jdbc.properties")
@Import({JdbcConfig.class,MybatiesConfig.class})
@EnableTransactionManagement//开启事务驱动
public class SpringConfig {
}
3.在业务层接口中添加事务管理
public interface AccountService {
@Transactional//添加事务管理
void transfer(String out,String in ,Double money);
}
事务添加到方法上表示当前方法开启事务,如果添加在整个接口上表示接口中所有方法开启事务