Spring之核心容器AOP

本文深入探讨了Spring的AOP(面向切面编程)概念,包括其降低耦合、提高代码复用性的核心价值。详细介绍了AOP的底层动态代理机制,通过JDK和CGLIB两种方式进行演示。此外,文章还阐述了AOP的相关术语,如连接点、切入点、通知和切面,并展示了如何配置和使用不同类型的AOP通知。最后,通过AspectJ注解和配置文件两种方式,展示了在Spring中实现AOP的实际操作步骤。
摘要由CSDN通过智能技术生成

Spring之核心容器AOP

一 AOP概念

1 什么是AOP

(1)AOP是面向切面编程,利用AOP可以对业务逻辑的各个 部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
(2)一句话描述:不通过修改源代码的方式,在主干概念里面添加新功能。
(3)案例说明
在这里插入图片描述

二 AOP底层原理

1 AOP使用动态代理

(1)第一种:有接口使用JDK动态代理
实现步骤:
① 定义一个接口及其实现类;
② 自定义 InvocationHandler 并重写invoke方法,在 invoke 方法中我们会调用原生方法(被代理类的方法)并自定义一些处理逻辑;
③ 通过 Proxy.newProxyInstance(ClassLoader loader,Class<?>[]
interfaces,InvocationHandler h) 方法创建代理对象;

方法中的三个参数:
第一个:类加载器
第二个:增强方法所在的类,这个类所实现的接口,支持多个接口
第三个:实现这个接口的InvocationHandler,创建代理对象,写增强的部分

案例如下:
第一步:创建接口,定义方法,及其实现类

//接口
public interface UserDao {
     public int add(int a,int b);
     public String update(String id);
}
//实现类
public class UserDaoImpl implements UserDao {
     @Override
     public int add(int a, int b) {
          return a+b;
     }
     @Override
     public String update(String id) {
        return id;
     }
}

第二步:创建自定义InvocationHandler

// 创建代理对象代码 
class UserDaoProxy implements InvocationHandler {     
	//1 把创建的是谁的代理对象,把谁传递过来     
	// 有参数构造传递     
	private Object obj;
    public UserDaoProxy(Object obj) {
             this.obj = obj;
    }    
    // 增强的逻辑 
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        
     	// 方法之前         
    	System. out .println("方法之前执行...."+method.getName()+" :传递的参 数..."+ Arrays. toString (args));         
     	// 被增强的方法执行         
     	Object res = method.invoke(obj, args);         
     	// 方法之后         
     	System. out .println("方法之后执行...."+obj);       
     	return res;     
    }
} 

第三步:使用Proxy创建代理对象

public class JDKProxy {
     public static void main(String[] args) {
     	  // 创建接口实现类代理对象
          Class[] interfaces = {UserDao.class};
          UserDaoImpl userDao = new UserDaoImpl();       
          UserDao dao = (UserDao)Proxy. newProxyInstance (JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao));
          int result = dao.add(1, 2);
          System. out .println("result:"+result);     
     }
} 

(2)第二种:没有实现接口,使用CGLIB动态代理
实现步骤:
① 定义一个类;
② 自定义 MethodInterceptor 并重写 intercept 方法,intercept 用于拦截增强被代理类的方法,和JDK 动态代理中的 invoke 方法类似;
③ 通过 Enhancer 类的 create()创建代理类;

案例
第一步:定义类

public class Base {
	/**
	 * 一个模拟的add方法
	 */
	public void add() {
		System.out.println("add ------------");
	}
}

第二步: 自定义 MethodInterceptor 并重写 intercept 方法

public class CglibProxy implements MethodInterceptor {
 
	public Object intercept(Object object, Method method, Object[] args,
			MethodProxy proxy) throws Throwable {
		// 添加切面逻辑(advise),此处是在目标类代码执行之前,即为MethodBeforeAdviceInterceptor。
		System.out.println("before-------------");
		// 执行目标类add方法
		proxy.invokeSuper(object, args);
		// 添加切面逻辑(advise),此处是在目标类代码执行之后,即为MethodAfterAdviceInterceptor。
		System.out.println("after--------------");
		return null;
	}
}

第三步:通过 Enhancer 类的 create()创建代理类

//创建工厂类
public class Factory {
	/**
	 * 获得增强之后的目标类,即添加了切入逻辑advice之后的目标类
	 * 
	 * @param proxy
	 * @return
	 */
	public static Base getInstance(CglibProxy proxy) {
		Enhancer enhancer = new Enhancer();
		enhancer.setSuperclass(Base.class);
		//回调方法的参数为代理类对象CglibProxy,最后增强目标类调用的是代理类对象CglibProxy中的intercept方法
		enhancer.setCallback(proxy);
		// 此刻,base不是单纯的目标类,而是增强过的目标类
		Base base = (Base) enhancer.create();
		return base;
	}
}

//测试类
public class Test {
	public static void main(String[] args) {
		CglibProxy proxy = new CglibProxy();
		// base为生成的增强过的目标类
		Base base = Factory.getInstance(proxy);
		base.add();
	}
}

三 AOP相关术语简介

1 连接点

连接点是类里面可以被增强的方法

2 切入点

切入点是实际被真正增强的方法

3 通知

(1)通知是实际增强的逻辑部分
(2)通知有许多种类型
①前置通知
② 后置通知
③ 环绕通知
④ 异常通知
⑤ 最终通知

4 切面

切面是一个把通知应用到切入点的过程动作。

四 AOP操作

1 准备工作

(1)spring框架一般都是基于AspectJ实现AOP操作
AspectJ不是Spring的组成部分,独立了AOP框架,一般把spring和AspectJ一起使用进行AOP操作
(2)基于AspectJ实现AOP操作有两种实现
① 基于XML配置文件实现
② 基于注解方式实现
(3)在项目工程种导入AOP相关依赖
在这里插入图片描述
(4) 切入点表达式
① 作用:知道对哪个类里的那个方法进行增强
② 语法结构: execution([权限修饰符] [返回类型] [类全路径] 方法名称 )
案例:对包下所有类里的方法进行增强
execution(* com.atguigu.dao.. (…))

五 AspectJ注解操作AOP

1 创建类
public class User {
     public void add() {
              System. out .println("add.......");
      }
}
2 创建增强类

在增强类里创建方法,让不同的方法代表不同通知类型

// 增强的类 public class UserProxy {
     public void before() { // 前置通知
         System. out .println("before......");
     }
 }
3 进行通知的配置

(1) 在spring配置文件中开启注解扫描

<? 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.xsd"> 
    <! -- 开启注解扫描 -- >
    <context:component-scan basepackage="com.atguigu.spring5.aopanno"></context:component-scan> 

(2) 使用注解创建User和UserProxy对象
在这里插入图片描述
(3) 在增强类上添加注解@Aspect

@Component
@Aspect
// 生成代理对象 
 public class UserProxy { 

(4) 在spring配置文件中开启生成代理对象

<! -- 开启 Aspect 生成代理对象 -- > <aop:aspectj-autoproxy></aop:aspectj-autoproxy> 
4 配置不同类型的通知

(1) 在增强类里,在作为通知方法上面添加通知类型注解,使用切入点表达式配置

// 增强的类
@Component @Aspect  
// 生成代理对象 
public class UserProxy {     
	// 前置通知     
	//@Before 注解表示作为前置通知     
	@Before(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")     
	public void before() {         
		System. out .println("before.........");     
	}     
	// 后置通知(返回通知)     
	@AfterReturning(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")     
	public void afterReturning() {         
		System. out .println("afterReturning.........");     
	}     
	// 最终通知     
	@After(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")     
	public void after() {         
		System. out .println("after.........");     
	}     
	// 异常通知     
	@AfterThrowing(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")     
	public void afterThrowing() {         
		System. out .println("afterThrowing.........");     
	}     
	// 环绕通知     
	@Around(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))")     
	public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {         
		System. out .println("环绕之前.........");         
		// 被增强的方法执行         
		proceedingJoinPoint.proceed();         
		System. out .println("环绕之后........."); 
	} 
} 
5 相同切入点抽取
// 相同切入点抽取 
@Pointcut(value = "execution(* com.atguigu.spring5.aopanno.User.add(..))") 
public void pointdemo() { }
 // 前置通知
 //@Before 注解表示作为前置通知 @Before(value = "pointdemo()")
public void before() {     
	System. out .println("before.........");
}
6 设置增强类优先级

对于多个增强类对同一个方法进行增强,需要设置增强类优先级
在增强类上面添加注解@Order(数字类型值),值越小优先级越高

@Component
@Aspect 
@Order(1) 
public class PersonProxy 
7 完全使用注解开发

创建配置类,不需要创建XML配置文件

@Configuration 
@ComponentScan(basePackages = {"com.atguigu"}) 
@EnableAspectJAutoProxy(proxyTargetClass = true) 
public class ConfigAop { } 

六 AspectJ配置文件操作AOP

1 创建两个类

创建增强类和被增强类,创建方法

public class Book{
     public void buy() {
              System. out .println("buy.......");
      }
}
// 增强的类 public class BookProxy {
     public void before() { // 前置通知
         System. out .println("before......");
     }
 }
2 在spring配置文件创建两个类对象
<! -- 创建对象 -- > 
<bean id="book" class="com.atguigu.spring5.aopxml.Book"></bean> 
<bean id="bookProxy" class="com.atguigu.spring5.aopxml.BookProxy"></bean>
3 在spring配置文件中配置切入点
<! -- 配置 aop 增强 -- > 
<aop:config>     
	<! -- 切入点 -- >     
	<aop:pointcut id="p" expression="execution(* com.atguigu.spring5.aopxml.Book.buy(..))"/>     
	<! -- 配置切面 -- >     
	<aop:aspect ref="bookProxy">         
		<! -- 增强作用在具体的方法上 -- >         
		<aop:before method="before" pointcut-ref="p"/>     
	</aop:aspect> 
</aop:config> 
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值