spring AOP实现原理

本文深入探讨了面向切面编程(AOP)的概念及其在代码重用性和降低耦合度方面的作用。通过实例展示了AOP如何通过预编译方式和运行期动态代理实现程序功能的统一维护,介绍了AOP的基本术语,如目标类、连接点、切入点、通知、织入、代理类和切面,并详细解析了AOP的实现原理,包括静态代理、JDK动态代理和cglib动态代理等方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

*为什么使用AOP

1.写死代码
接口

public interface UserService{

	public  void add();
	public  void delete();
	public 	void updata(); 
}

实现类

public class UserServiceImp implements UserService {

    @Override
   	public  void add(){
   		System.out.println("Before");
   		System.out.println("add ");
   		System.out.println("After");
   	}
   	public  void delete(){
   		System.out.println("Before");
   		System.out.println("delete ");
   		System.out.println("After");
   	}
   	public  void updata(){
   		System.out.println("Before");
   		System.out.println("updata ");
   		System.out.println("After");
   	}

    private void before() {
        System.out.println("Before");
    }

    private void after() {
        System.out.println("After");
    }
}

before() 与 after() 方法写死在 sayHello() 方法体中了.那么你每实现一个类都要给类中加入这两个方法,很不符合代码的可重用性。所以我们要引入AOP这个概念。我们要将befor(),after()这种方法定义在一个切面类里面,当要使用时把它们织入(weaving)到目标类中*。通俗来讲就相当于一把刀去切一坨面,而对于面而来,我们就一定是横着来切它,这种简称为“横切”,下面我们就要来讲如何来实现这把刀。*

1.AOP概述

1)在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。
2)AOP是OOP(面向对象编程)的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。
3)利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
4)AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码
5)经典应用:事务管理、性能监视、安全检查、缓存 、日志等
6)Spring AOP使用纯Java实现,不需要专门的编译过程和类加载器,在运行期通过代理方式向目标类织入增强代码
7)AspectJ是一个基于Java语言的AOP框架,Spring2.0开始,Spring AOP引入对Aspect的支持,AspectJ扩展了Java语言,提供了一个专门的编译器,在编译时提供横向代码的织入

2.AOP的术语

1.target:目标类,需要被代理的类。例如:UserService
2.Joinpoint(连接点):所谓连接点是指那些可能被拦截到的方法。例如:所有的方法
3.PointCut 切入点:已经被增强的连接点。例如:addUser()
4.advice 通知/增强,增强代码。例如:after、before
5. Weaving(织入):是指把增强advice应用到目标对象target来创建新的代理对象proxy的过程.
6.proxy 代理类
7. Aspect(切面): 是切入点pointcut和通知advice的结合
一个线是一个特殊的面。
一个切入点和一个通知,组成成一个特殊的面。

在这里插入图片描述

3.AOP实现原理

  •   **AOP底层使用代理机制进行实现**
    

4.静态代理

最简单的解决方案就是使用静态代理模式了,我们单独为 UserServiceImpl 这个类写一个代理类:
UserServiceProxy.java

package com.liheng.proxy;

import com.liheng.service.UserService;
import com.liheng.service.UserServiceImp;

public class UserServiceProxy implements UserService {
	private UserServiceImp userService;
	
	public UserServiceProxy(UserServiceImp userService) {
		
		this.userService = userService;
	}

	   @Override
	   	public  void add(){
	   		System.out.println("Before");
	   		System.out.println("add ");
	   		System.out.println("After");
	   	}
	   	public  void delete(){
	   		System.out.println("Before");
	   		System.out.println("delete ");
	   		System.out.println("After");
	   	}
	   	public  void updata(){
	   		System.out.println("Before");
	   		System.out.println("updata ");
	   		System.out.println("After");
	   	}

	    private void before() {
	        System.out.println("Before");
	    }

	    private void after() {
	        System.out.println("After");
	    }
	
}


UserTest.java:

package com.liheng.test;

import org.junit.Test;

import com.liheng.proxy.UserServiceProxy;
import com.liheng.service.UserService;
import com.liheng.service.UserServiceImp;

public class UserTest {
	@Test
	public void test(){
		UserService userServiceProxy = new UserServiceProxy(new UserServiceImp());
		userServiceProxy.add();
		userServiceProxy.delete();
		userServiceProxy.updata();
	}
}

这样写没错,但是有个问题,XxxProxy 这样的类会越来越多,如何才能将这些代理类尽可能减少呢?最好只有一个代理类。

5.JDK动态代理

接口:

public interface UserService {
	public  void add();
	public  void delete();
	public 	void updata(); 
}

实现类:

public class UserServiceImp implements UserService {

	@Override
	public void add() {
		System.out.println("add User");
		
	}

	@Override
	public void delete() {
		System.out.println("delete User");
		
	}

	@Override
	public void updata() {
		System.out.println("updata User");
		
	}

}

我们将before(),after()这两个方法放到一个切面类中:

package com.liheng.proxy;

public class MyAspect {
	  public void before() {
	        System.out.println("Before");
	    }

	  public void after() {
	        System.out.println("After");
	    }
	
}

代理工厂类,用来生产代理对象:

package com.liheng.factoty;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import com.liheng.proxy.MyAspect;
import com.liheng.service.UserService;
import com.liheng.service.UserServiceImp;

public class ProxyFactory {
	public  UserService createUserService(){
//		1.目标类
		final UserService userService = new UserServiceImp();
//		2.切面类
		final MyAspect myAspect = new MyAspect();
//		3.代理类  将切面类通知到目标类中
	/*	newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
	 * 参数1.类加载器,一般写当前类
	 * 参数2.被代理类对象要实现的接口
	 * 参数3.处理类,一般写匿名类
	 * */
		UserService proxy =(UserService) Proxy.newProxyInstance(
				ProxyFactory.class.getClassLoader(), 
				userService.getClass().getInterfaces(),
				new InvocationHandler() {
					
					@Override
					public Object invoke(Object proxy, Method method, Object[] args)
							throws Throwable {
						myAspect.before();
						//	放行
						Object obj = method.invoke(userService, args);
						
						myAspect.after();
						return obj;
					}
				});
		return proxy;
	}
}

测试类:

package com.liheng.test;

import org.junit.Test;

import com.liheng.factoty.ProxyFactory;
import com.liheng.service.UserService;

public class UserTest2 {
	@Test
	public void test(){
		UserService userService = new ProxyFactory().createUserService();
		userService.add();
	}
}

在这里插入图片描述

6.cglib动态代理实现

我们使用开源的 CGLib 类库可以代理没有接口的类,这样就弥补了 JDK 的不足
在这里插入图片描述在这里插入图片描述
cjlib和JDK代理的区别
JDK动态代理只能对实现了接口的类生成代理,而不能针对类 。
CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法 。
因为是继承,所以该类或方法不要声明成final ,final可以阻止继承和多态。

7.AOP联盟实现半自动代理

需要多导入两个jar包
在这里插入图片描述切面类:
在这里插入图片描述beans.xml
在这里插入图片描述

8.AOP全自动编程

在这里插入图片描述在这里插入图片描述9.AspectJ实现AOP
接口

package com.liheng.service;

public interface IUserService {
	public void addUser();
	public void deleteUser();
	public void updataUser();
	public int deleteUser(int id);
}

实现类

package com.liheng.service;

public class UserServiceImp implements IUserService{

	@Override
	public void addUser() {
		System.out.println("add User");
		
	}

	@Override
	public void deleteUser() {
		System.out.println("delete User");
		
	}

	@Override
	public void updataUser() {
		System.out.println("updata User");
		
	}

	@Override
	public int deleteUser(int id) {
		
		return id;
	}

	

}

切面类

package com.liheng.aspect;

import org.aspectj.lang.ProceedingJoinPoint;

public class MyAspect {
	public void before(){
		System.out.println("前置通知");
	}
	public void afterReturning(){
		System.out.println("后置通知");
	}
	public Object  around(ProceedingJoinPoint pjp) throws Throwable{
		System.out.println("环绕通知");
//		System.out.println("开启事务");
//		放行
		Object obj = pjp.proceed();
		
//		System.out.println("提交事务");
		return obj;
	}
}

beans.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: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">


<bean id ="userService" class="com.liheng.service.UserServiceImp"></bean>
<bean id = "myAspect" class= "com.liheng.aspect.MyAspect"></bean>

<aop:config>
	<aop:aspect ref="myAspect">
		<aop:pointcut id="myPointcut" expression="execution(* com.liheng.service.UserServiceImp.*(..))"/>
		<aop:before method="before" pointcut-ref="myPointcut"/>
		<aop:after-returning method="afterReturning" pointcut-ref="myPointcut"/>
		<aop:around method="around" pointcut-ref="myPointcut"/>
	</aop:aspect>
</aop:config>
</beans>

测试类

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.liheng.service.IUserService;


public class TestDemo {
	@Test
	public void test(){
		ApplicationContext context = new ClassPathXmlApplicationContext("beans4.xml");
		IUserService userService = (IUserService) context.getBean("userService");
		userService.addUser();
	}
}

给一张思维导图,总结一下知识点
在这里插入图片描述
Sp

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值