Spring5详细笔记2(AOP)

1、Spring 框架概述
2、IOC 容器

3、AOP

  AOP(概念)
  AOP(底层原理)
  AOP(JDK 动态代理)
  AOP(CGLIB动态代理)
  AOP 的开发中的相关术语
  AOP 操作(AspectJ 注解)
  AOP 操作(xml 方式)

4、JdbcTemplate
5、事务管理
6、Spring5 新特性

AOP

AOP(概念)

1、什么是 AOP
(1)面向切面编程(方面),利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

(2)通俗描述:不通过修改源代码方式,在主干功能里面添加新功能

(3)使用登录例子说明 AOP

在这里插入图片描述

AOP(底层原理)

1、AOP 底层使用动态代理
(1)有两种情况动态代理
第一种 有接口情况,使用 JDK 动态代理
 创建接口实现类代理对象,增强类的方法
在这里插入图片描述

第二种 没有接口情况,使用 CGLIB 动态代理
 创建子类的代理对象,增强类的方法
在这里插入图片描述

AOP(JDK 动态代理)

1、使用 JDK 动态代理,使用 Proxy 类里面的方法创建代理对象
(1)调用 newProxyInstance 方法
在这里插入图片描述
方法有三个参数: 第一参数,类加载器
第二参数,增强方法所在的类,这个类实现的接口,支持多个接口
第三参数,实现这个接口 InvocationHandler,创建代理对象,写增强的部分

2、编写 JDK 动态代理代码
(1)创建接口,定义方法

public interface UserDao { 
    public int add(int a,int b); 
    public String update(String id); 
} 

(2)创建接口实现类,实现方法

public class UserDaoImpl implements UserDao { 
    @Override 
    public int add(int a, int b) { 
        return a+b; 
    } 
    @Override 
    public String update(String id) { 
        return id; 
    } 
} 

(3)使用 Proxy 类创建接口代理对象
  第一种实现方式,实现InvocationHandler接口

public class MyJDKProxy implements InvocationHandler {
	private UserDao userDao;
	public MyJDKProxy(UserDao userDao) {
		this.userDao = userDao; 
	}
	// 编写工具方法:生成代理:
	public UserDao getUserDaoImplProxy(){
	UserDao userDaoProxy = (UserDao)Proxy.newProxyInstance(
		userDao.getClass().getClassLoader(),
		userDao.getClass().getInterfaces(), 
		this);
	return userDaoProxy; 
	}
		@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		if("save".equals(method.getName())){
		System.out.println("权限校验================");
		}
		return method.invoke(userDao, args);
	}
}

  第二种实现方式,使用匿名内部类

public class GetUserDaoProxy {
	// 编写工具方法:生成代理:
	public static UserDao getUserDaoImplProxy(UserDao userDao){
		UserDao userDaoProxy = (UserDao)Proxy.newProxyInstance(
			userDao.getClass().getClassLoader(),
			userDao.getClass().getInterfaces(), 
			new InvocationHandler(){
				@Override
				public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
					if("save".equals(method.getName())){
						System.out.println("权限校验================");
					}
					return method.invoke(userDao, args);
				}
			});
		return userDaoProxy;
	}
}

(3)编写测试类

@Test
void testJDKProxy() {
    System.out.println("增强前------------------");
    UserDao userDao = new UserDaoImpl();
    userDao.add();
    userDao.delete();
    userDao.save();
    userDao.update();
    System.out.println("\n增强后------------------");
    UserDao userDaoProxy = UserDaoProxy.getUserDaoImplProxy(userDao);
    userDaoProxy.add();
    userDaoProxy.delete();
    userDaoProxy.save();
    userDaoProxy.update();
}

(4)运行结果
在这里插入图片描述

AOP(Cglib 动态代理)

1、编写 Cglib动态代理代码
(1)创建CustomerDao类

public class CustomerDao {
	public void save(){
		System.out.println("保存----------");
	}
	public void add(){
		System.out.println("增加----------");
	}
	public void delete(){
		System.out.println("删除----------");
	}
	public void update(){
		System.out.println("更新----------");
	}
}

(2)创建CustomerDao代理类,实现MethodInterceptor接口

public class MyCglibProxy implements MethodInterceptor{
	private CustomerDao customerDao;
	public MyCglibProxy(CustomerDao customerDao){
		this.customerDao = customerDao; 
	}
	// 生成代理的方法:
	public CustomerDao createProxy(){
		// 创建 Cglib 的核心类:
		Enhancer enhancer = new Enhancer();
		// 设置父类:
		enhancer.setSuperclass(CustomerDao.class);
		// 设置回调:
		enhancer.setCallback(this);
		// 生成代理:
		CustomerDao customerDaoProxy = (CustomerDao) enhancer.create();
		return customerDaoProxy; 
	}
	@Override
	public Object intercept(Object proxy, Method method, Object[] args, MethodProxy 
	methodProxy) throws Throwable {
		if("delete".equals(method.getName())){
			Object obj = methodProxy.invokeSuper(proxy, args);
			System.out.println("日志记录================");
			return obj; 
		}
	return methodProxy.invokeSuper(proxy, args);
	} 
}

(3)编写测试类

@Test
void testCglibProxy() {
    System.out.println("增强前------------------");
    CustomerDao customerDao = new CustomerDao();
    customerDao.add();
    customerDao.delete();
    customerDao.save();
    customerDao.update();
    System.out.println("\n增强后------------------");
    CustomerDao customerDaoProxy = new CustomerDaoCglibProxy(customerDao).createProxy();
    customerDaoProxy.add();
    customerDaoProxy.delete();
    customerDaoProxy.save();
    customerDaoProxy.update();
}

(4)运行结果
在这里插入图片描述

AOP 的开发中的相关术语

Joinpoint(连接点): 所谓连接点是指那些被拦截到的点。在 spring 中,这些点指的是方法,因为spring 只支持方法类型的连接点.
Pointcut(切入点): 所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义.
Advice(通知/增强):所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)
Introduction(引介):引介是一种特殊的通知在不修改类代码的前提下, Introduction 可以在运行期为类动态地添加一些方法或 Field.
Target(目标对象):代理的目标对象
Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程.spring 采用动态代理织入,而 AspectJ 采用编译期织入和类装载期织入
Proxy(代理): 一个类被 AOP 织入增强后,就产生一个结果代理类
Aspect(切面): 是切入点和通知(引介)的结合

切入点表达式
(1)切入点表达式作用:知道对哪个类里面的哪个方法进行增强
(2)语法结构: execution([权限修饰符] [返回类型] [类全路径] [方法名称]([参数列表]) )

举例 1:对 com.zsm.dao.BookDao 类里面的 add 进行增强
execution(* com.zsm.dao.BookDao.add(…))

举例 2:对 com.zsm.dao.BookDao 类里面的所有的方法进行增强
execution(* com.zsm.dao.BookDao.* (…))

AOP 操作(AspectJ 注解)

1、创建目标类ProductDao,在类里面定义方法

@Component
public class ProductDao{
	public void save() {
		System.out.println("ProductDaoImpl 中的save方法执行了。。。");
	}

	public String delete() {
		System.out.println("ProductDaoImpl 中的delete方法执行了。。。");
		return "李白";
	}
	
	public void update() {
		System.out.println("ProductDaoImpl 中的update方法执行了。。。");
	}
	
	public void find() {
		System.out.println("ProductDaoImpl 中的find方法执行了。。。");
		int i = 1/0;
	}
}

2、创建切面类,在类里面定义要增强的功能

@Component
@Aspect
public class ProductDaoAspectJ{
    // 前置通知
    @Before(value = "execution(* com.zsm.aop.dao.ProductDao.save(..))")
    public void checkPri() {
        System.out.println("权限校验===========>-------前置通知");
    }
    // 后置通知(返回通知)
    @AfterReturning(value = "execution(* com.zsm.aop.dao.ProductDao.delete(..))",returning = "ex")
    public void afterReturning(Object ex) {
        System.out.println("日志记录===========>-------后置通知++++++++>" + ex);
    }
    // 环绕通知
    @Around(value = "pointcut1()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("日志记录===========>-------环绕通知前");
        Object object = joinPoint.proceed();
        System.out.println("日志记录===========>-------环绕通知后");
        return object;
    }

    // 异常通知		在被增强方法中出现异常的时候执行
    @AfterThrowing(value = "execution(* com.zsm.aop.dao.ProductDao.find(..))", throwing = "ex")
    public void name(Throwable ex) {
        System.out.println("异常通知=============>" + ex.getMessage());
    }

    // 最终通知
//	@After(value = "execution(* com.zsm.aop.dao.ProductDao.find(..))")
//	public void after() {
//		System.out.println("最终通知=============>");
//	}

    // 最终通知
    @After(value = "ProductDaoAspectJ.pointcut()")
    public void after() {
        System.out.println("最终通知=============>");
    }

// 相同的切入点抽取
    @Pointcut(value = "execution(* com.zsm.aop.dao.ProductDao.find(..))")
    private void pointcut() {}
    @Pointcut(value = "execution(* com.zsm.aop.dao.ProductDao.update(..))")
    private void pointcut1() {}
}

3、编写测试类


@Resource
private ProductDao productDao;

@Test
void testAspectJ() {
    productDao.save();
    productDao.delete();
    productDao.update();
    productDao.find();
}

4、运行结果
在这里插入图片描述
5、有多个增强类对同一个方法进行增强,设置增强类优先级
(1)在增强类上面添加注解 @Order(数字类型值),数字类型值越小优先级越高

@Component
@Aspect
@Order(1) 
public class ProductDaoAspectJ
AOP 操作(xml 方式)

1、创建目标类OrderDao,在类里面定义方法

public class OrderDao {
	public void save() {
		System.out.println("保存订单...");
	}
	
	public void update() {
		System.out.println("修改订单...");
	}
	
	public void delete() {
		System.out.println("删除订单...");
	}
	
	public void find() {
		System.out.println("查询订单...");
	}
}

2、创建切面类,在类里面定义要增强的功能

public class MyAspectXml {
	// 前置通知
	public void before(){
		System.out.println("前置通知===========");
	}
	// 后置通知
	public void afterReturing(){
		System.out.println("后置通知===========");
	}
	// 环绕通知
	public void around(){
		System.out.println("环绕通知===========");
	}
	// 异常通知
	public void afterThrowing(){
		System.out.println("异常通知===========");
	}
	// 最终通知
	public void after(){
		System.out.println("最终通知===========");
	}
}

3、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: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/aop 
 http://www.springframework.org/schema/aop/spring-aop.xsd">
	<!-- 配置切面类 -->
	<bean id="myAspectXml" class="com.zsm.aop.xml.MyAspectXml"></bean>
	<!-- 进行 aop 的配置 -->
	<aop:config>
		<!-- 配置切入点表达式:哪些类的哪些方法需要进行增强 -->
		<aop:pointcut expression="execution(* com.zsm.aop.dao.*Dao.save(..))" id="pointcut1"/>
		<aop:pointcut expression="execution(* com.zsm.aop.dao.*Dao.delete(..))" id="pointcut2"/>
		<aop:pointcut expression="execution(* com.zsm.aop.dao.*Dao.update(..))" id="pointcut3"/>
		<aop:pointcut expression="execution(* com.zsm.aop.dao.*Dao.find(..))" id="pointcut4"/>
		<!-- 配置切面 -->
		<aop:aspect ref="myAspectXml">
			<aop:before method="before" pointcut-ref="pointcut1"/>
			<aop:after-returning method="afterReturing" pointcut-ref="pointcut2"/>
			<aop:around method="around" pointcut-ref="pointcut3"/>
			<aop:after-throwing method="afterThrowing" pointcut-ref="pointcut4"/>
			<aop:after method="after" pointcut-ref="pointcut4"/>
		</aop:aspect>
	</aop:config>
</beans>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值