Spring框架 (17) —— 基于注解配置AOP

基于注解配置AOP

搭建环境

第一步:创建一个Java项目

创建一个Java项目,加入Spring框架的基础支持包

在这里插入图片描述

第二步:编写业务层类和接口

UserService 接口

package cn.xc.spring.service;

import cn.xc.spring.pojo.User;

public interface UserService {
	void insert(User user);
	void update(User user);
}

业务层UserServiceImpl 实现类

package cn.xc.spring.service.impl;

import cn.xc.spring.pojo.User;
import cn.xc.spring.service.UserService;

@Service
public class UserServiceImpl implements UserService{
	
	public void insert(User user) {
		System.out.println("---调用DAO层保存方法---");
	}
	public void update(User user) {
		System.out.println("---调用DAO层修改方法---");
	}
}

第三步:编写Spring配置文件

<?xml version="1.0" encoding="UTF-8"?>
<!-- Spring配置的根元素+约束 -->
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:p="http://www.springframework.org/schema/p"
	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-4.3.xsd">
	
	<!-- 配置注解扫描包位置 -->
	<context:component-scan base-package="cn.xc.spring"/>
	</beans>

第四步:编写测试代码

package cn.xc.spring.test;

import javax.annotation.Resource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import cn.xc.spring.pojo.User;
import cn.xc.spring.service.impl.UserServiceImpl;

@RunWith(SpringJUnit4ClassRunner.class)
//读取Spring配置文件 xml
//@ContextConfiguration("classpath:applicationContext.xml")
//读取Spring配置文件 java类做配置文件
@ContextConfiguration(classes = {SpringConfig.class})
public class UserServiceTest {

	@Resource
	private UserServiceImpl service;

	@Test
	public void testSave() {
		User user = new User(null, "张三", "zhangsan@qq.com");
		service.insert(user);
	}

	@Test
	public void testUpdate() {
		User user = new User(1, "李四", "lisi@qq.com");
		service.update(user);
	}
}

配置AOP

第一步:加入AOP的支持包

–注意:必须要导入加入支持AOP的包。
Spring的AOP包基于AspectJ框架,所以必须加入AspectJ–>aspectjweaver.jar

在这里插入图片描述

第二步:编写一个切面类

package cn.xc.spring;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
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 //在此类中可以使用注解进行aop的相关配置 <aop:aspect>
public class TransactionManagerHandler {
	
	//<aop:pointcut expression="execution( * cn.zj.spring.service..*.*(..))" id="当前方法名就是id"/>
	@Pointcut("execution( * cn.xc.spring.service..*.*(..))")
	public void pointcut() {}
	
	@Before("pointcut()") //<aop:before method="begin" pointcut-ref="pt"/>
	public void begin() {
		System.out.println("开启事务");
	}
	
	@AfterReturning("pointcut()")//<aop:after-returning method="commit" pointcut-ref="pt"/> 
	public void commit() {
		System.out.println("提交事务");
	}
	
	//<aop:after-throwing  throwing="e"  method="rollback" pointcut-ref="pt"/>
	@AfterThrowing(pointcut="pointcut()",throwing="ex")
	public void rollback(Throwable ex) {
		System.out.println("注解的回滚事务 : " + ex.getMessage());
	}
	
	@After("pointcut()")//<aop:after method="close"  pointcut-ref="pt"/>
	public void close() {
		System.out.println("关闭session");
	}
	
	//环绕增强
	@Around("pointcut()") //<aop:around method="allInOne" pointcut-ref="pt"/>
	public Object allInOne(ProceedingJoinPoint pjp) {
		Object result = null;
		try {
			System.out.println("开启事务------");
			//执行被代理对象当前需要执行业务方法
			result = pjp.proceed();
			System.out.println("提交事务------");
		} catch (Throwable ex) {
			System.out.println("------回滚事务 : " + ex.getMessage());
		}finally {
			System.out.println("关闭session------");
		}
		return result;
	}
}

第三步:配置AOP配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    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.xsd
    ">
   <!-- 配置spring的包扫描 -->
   <context:component-scan base-package="cn.xc.spring"/>	
   <!-- 使用注解配置AOP配置配置自动注入AOP -->
   <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

</beans>

纯注解配置

package cn.xc.spring.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@ComponentScan("cn.xc.spring")
@EnableAspectJAutoProxy //开启aop注解配置
public class SpringConfig {

}

常用注解

@Aspect

作用:
把当前类声明为切面类。

@Before

作用:
把当前方法看成是前置通知。
属性:
value:用于指定切入点表达式,还可以指定切入点表达式的引用。

@AfterReturning

作用:
把当前方法看成是最终通知。报异常,就不执行
属性:
value:用于指定切入点表达式,还可以指定切入点表达式的引用。

@AfterThrowing

作用:
把当前方法看成是异常通知。只有报异常才执行

属性:
value:用于指定切入点表达式,还可以指定切入点表达式的引用。

@After

作用:
把当前方法看成是后置通知。不管报不报异常都执行
属性:
value:用于指定切入点表达式,还可以指定切入点表达式的引用。

@Around

作用:
把当前方法看成是环绕通知。
属性:
value:用于指定切入点表达式,还可以指定切入点表达式的引用。

@Pointcut

作用:
指定切入点表达式
属性:
value:指定表达式的内容

小结

AOP 面向切面切面编程

为什么要有AOP 编程?
问题:service层在实际开发中要处理事务,日志等操作,这些操作是和业务无关代码,但是又不能少,而且每个方法都有,大量重复,如何把这些代码抽取出去

解决方案:此种场景只能使用Java的动态代理技术解决。为Service层的类创建代理对象。在代理对象中为 各个方法进行增强,使用的时候直接面向代理对象。调用代理对象方法。代理对象底层还是会调用真实对象的方法,但是在 方法执行之前,之后,异常,最终都可以做相应增强

代理模式
Java中有一种设计模式,就是代理模式,讲解就上面问题解决方案,是一种思想

动态代理技术 :实际上就是对代理模式思想的一种具体实现

  1. JDK动态代理-Java官方
    (1) 使用方法
    Object proxy = Proxy.newProxuInstacne(classLoader,interfaces,h)
  1. classLoader: 类加载
  2. 被代理对象的接口的字节码实例
  3. 处理器,开发者具体做增的地方
    a. 开发需要自己创建匿名内部内
    (2) 缺点:只能代理有接口的类
  1. CGLIB 第三方代理
    (1) 使用方法
    ① Enhancer
    (2) 优点:既可以代理有接口的,又可以代理没有接口的类
    ① 但是不能代理 final 修饰类或者方法

动态代理能解决主要问题:代码重复问题,但是引来新的小问题(所有方法都代理,不能按照指定规则配置代理方法等等)

SpringAOP ,Spring的AOP在代理的基础之上,增加可以 指定规则 配置对应的代理

SpringAOP 开发者不需要写过多的程序主要编写 Spring配置代码

  1. SpringAOPxml配置
    (1) 在xml配置文件中引入新的 aop 命名空间
    (2) Springaop xml配置标签
    ① <aop:config> 开启aop配置,aop所有配置都在此标签内部配置
  1. <aop:ponitcut exepression=”切入点语法” id=””> 配置切入点
  2. <aop:apect ref=“引入要增强的bean(模拟事务管理器)”> 配置切面
    a. <aop:before>前置通知
    b. <aop:aftereturning>后置通知
    c. <aop:afterthrowing>异常通知
    d. <aop:after>最终通知
    e. <aop:around>环绕通知
  1. SpringAOP注解配置
    (1) 在配置文件汇总开启注解配置
    <aop:aspectj-autoproxy/>
    (2) 纯注解,再 Spring的java配置类上面贴上注解
    ① @EnableAspectJAutoProxy
    (3) @Aspect 在类贴上这个注解,把对应的类当前切面配置类
    (4) @Pointcut 切入点注解
    (5) @Before 前置通知注解
    (6) @After 后置通知注解
    (7) @Aftertrhowing 异常通知注解
    (8) @Afterreturing 最终通知注解
    (9) @Around 环绕通知注解
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值