Spring AOP基本介绍

AOP是Spring框架除了IOC之外的另一个核心概念。
我们知道Java是面向对象编程(OOP)的语言,也就是将所有的一切都看成对象,通过对象与对象之间相互作用来解决问题的一种编程思想。而AOP是OOP的一个补充:在运行时,动态地将代码切入到类的指定方法、指定位置上的编程思想就是面向切面的编程。
AOP的优点如下:

  • 降低模块之间的耦合度
  • 使系统容易扩展
  • 更好的进行代码复用
  • 非业务代码更加集中不分散,便于统一管理
  • 业务代码更加简洁纯粹

下面通过代码展示一下什么是AOP
先创建一个接口模拟添加用户和删除用户

public interface UserDao{
	public void addUser();
	public void deleteUser();
}

创建接口的实现类UserDaoImpl

public class UserDaoImpl implements UserDao{
	public void addUser(){
		System.out.println("正在添加用户");
	}
	public void deleteUser(){
		System.out.println("正在删除用户");
	}
}

在测试方法中创建UserDaoImpl对象并且调用方法

public class UserDaoTest{
	public static void main(String[] args){
		UserDao userDao = new UserDaoImpl();
		userDao.addUser();
		userDao.deleteUser();
	}
}

上面写了简单的业务代码,现在添加一个功能,就是在每一个方法执行的时候打印日志信息,可以在每个方法前后输出提示信息这样简单地实现

public class UserDaoImpl implements UserDao{
	public void addUser(){
		System.out.println("addUser方法执行之前");
		System.out.println("正在添加用户");
		System.out.println("addUser方法执行之后");
	}
	public void deleteUser(){
		System.out.println("deleteUser方法执行之前");
		System.out.println("正在删除用户");
		System.out.println("deleteUser方法执行之后");
	}
}

这样功能就已经实现,但是这种方式让业务代码和日志代码耦合度非常高,不利于后期维护。
我们可以发现,每个方法中的日志信息相似度非常高,那么有没有可能将这部分代码抽取出来进行封装以便统一维护呢?按照这样的思考角度,我们要做的就是把上面方法中同个位置的代码抽取出来形成一个切面,将这个切面封装成一个对象,将所有的日志代码封装到这个对象中去。这就是AOP的思想。

如何实现AOP呢?

可以使用动态代理的方式来实现。
我们希望UserDaoImpl只进行业务代码,不进行打印日志的工作,那么就需要一个对象来代替UserDaoImpl实现日志功能,这个对象就是代理对象。要想让这个代理对象能打印每个方法的日志功能,首先它要具备被代理对象的所有功能,然后在这基础上扩展日志功能。
首先,删除UserDaoImpl类中打印日志的部分

public class UserDaoImpl implements UserDao{
	public void addUser(){
		System.out.println("正在添加用户");
	}
	public void deleteUser(){
		System.out.println("正在删除用户");
	}
}

然后创建InvocationHandlerImpl类实现InvocationHandler接口,作为一个动态代理类。

public class InvocationHandlerImpl implements InvocationHandler{
	//声明目标类接口
	private UserDao userDao;
	//创建代理方法
	public Object createProxy(UserDao userDao){
		this userDao = userDao;
		//类加载器
		ClassLoader classLoader = UserDao.class.getClassLoader();
		//被代理对象实现的所有接口
		Class[] classes = userDao.getClass().getInterfaces();
		//返回代理后的对象
		return Proxy.newProxyInstance(classLoader,classes,this);
	}
	public Object invoke(Object proxy,Method method,Object[] args)throws Throwable{
		System.out.println(method.getName()+"方法执行之前");
		Object obj = method.invoke(userDao,args);
		System.out.println(method.getName()+"方法执行之后");
		return obj;
	}
}

上面代码中,createProxy方法是InvacationHandlerImpl类提供给外部调用的方法,传入需要被代理的对象,createProxy方法会返回一个代理对象。
createProxy方法完成了两项工作:
1、将外部传进来的被代理对象保存到成员变量中,因为业务方法调用时需要用到被代理对象。
2、通过Proxy.newProxyInstance方法创建一个代理对象。其中Proxy.newProxyInstance方法的参数解释如下:
(1)Java中对象是JVM根据运行时类来创建的,此时需要动态创建一个代理对象,可以使用被代理对象的运行时类来创建代理对象:ClassLoader classLoader = userDao.class.getClassLoader(); 获取的是被代理对象的运行时类。
(2)同时代理对象需要具备被代理对象的所有功能,即需要拥有被代理对象的所有接口,Class[] classes = userDao.getClass().getInterfaces(); 就是执行这一功能。
method.invoke()是通过反射机制来调用被代理对象的方法,即业务方法。
所以在method.invoke()前后添加打印日志信息,就等同于在被代理对象业务方法前后添加打印日志信息,这样就做到了业务代码与日志代码分离。
创建测试类

public class Test{
	public static void main(String[] args){
		//被代理对象
		UserDao userDao = new UserDaoImpl();
		InvovationHandlerImpl  ihi = new InvocationHandlerImpl();
		//代理对象
		UserDao userDao2 = (UserDao)ihi.createProxy(userDao);
		userDao2.addUser();
		userDao2.deleteUser();
	}
}

执行结果如图:
在这里插入图片描述
以上是通过jdk动态代理实现AOP的方法。但是在Spring框架中不需要那么复杂,Spring已经对这个过程进行了封装。
在Spring框架中,不需要创建一个动态代理类,而是创建一个切面类,Spring底层会自动根据切面类以及目标类生成一个代理对象。
创建一个切面类

@Aspect
@Component
public class MyAspect{
	@Before("execution(* com.aspect.UserDaoImpl.*(..))")
	public void before(JoinPoint joinPoint){
		//获取方法名
		String name = joinPoint.getSignature().getName();
		System.out.println(name+"方法执行之前");
	}
	
	@After("execution(* com.aspect.UserDaoImpl.*(..))")
	public void after(JoinPoint joinPoint){
		String name = joinPoint.getSignature().getName();
		System.out.println(name+"方法执行之后");
	}
}

在上面的代码中,以before方法做说明,@Before注解表明before方法在方法执行之前执行,execution(* com.aspect.UserDaoImpl.*(..))表示切入点是
com.aspect包下的UserDaoImpl类中的所有方法。After方法同理。同时目标类也需要加注解@Component

@Component(value="userDao")
public class UserDaoImpl implements UserDao{
	public void addUser(){
		System.out.println("正在添加用户");
	}
	public void deleteUser(){
		System.out.println("正在删除用户");
	}
}

在spring.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"
    xmlns:context="http://www.springframework.org/schema/context"
    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-4.0.xsd
        http://www.springframework.org/schema/aop 
        http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
	<!--自动扫描-->
	<context:component-scan base-package="com.aspect"></context:component-scan>
	<!--使Aspect注解生效,为目标类自动生成代理对象-->
	<aop:aspect-autoproxy></aop:aspect-autoproxy>
</beans>

1、将com.aspect包中的类扫描到IOC容器中
2、添加aop:aspect-autoproxy注解,Spring容器会结合切面类和目标类自动生成动态代理对象,Spring框架的AOP底层就是通过动态代理方式完成AOP的。
创建测试类

public class Test{
	public static void main(String[] args){
		//加载配置文件
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
		//获取代理对象
		UserDao userDao = (UserDao)applicationContext.getBean("userDao");
		userDao.addUser();
		userDao.deleteUser();
	}
}

执行结果如图
在这里插入图片描述
以上就是简单的用注解的方式实现Spring框架的aop。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring AOP(面向切面编程)是 Spring 框架的一个模块,它提供了一种在程序运行期间动态代理类的机制,以便能够在不修改原始代码的情况下,实现诸如日志记录、性能统计、安全控制等横向关注点的功能。Spring AOP 基于代理模式实现,通过代理对象包装目标对象,从而实现在目标方法执行前、执行后、执行异常、执行返回时等时刻,插入一些额外的逻辑。下面是 Spring AOP基本操作: 1. 定义切面类:切面类包含了一系列的通知(Advice),通知描述了切面类在何时执行某个操作。 2. 定义切入点:切入点指定了哪些类的哪些方法会被切面类的通知所拦截。 3. 定义通知:通知是切面类的方法,它描述了切面类在拦截到切入点处的程序执行时,应该执行的操作。Spring AOP 提供了五种类型的通知: - Before:在目标方法执行前执行通知。 - After:在目标方法执行后执行通知。 - AfterReturning:在目标方法执行后返回结果时执行通知。 - AfterThrowing:在目标方法抛出异常时执行通知。 - Around:在目标方法执行前后都执行通知。 4. 配置切面:切面需要在 Spring 的配置文件进行配置,以便将切面类与切入点关联。 5. 启用 AOP:启用 AOP 需要在 Spring 的配置文件配置 <aop:aspectj-autoproxy /> 标签。 通过以上基本操作,就可以在 Spring 使用 AOP 实现对目标对象的拦截和增强。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值