AOP实现过程及分析

一、AOP

AOP(Aspect Oriented Programming 面向切面编程)是一种通过运行期动态代理实现代码复用的机制,是对传统OOP(Object Oriented Programming,面向对象编程 )的补充。目前,Aspectj是Java社区里最完整最流行的AOP框架,在Spring 2.0以上版本中可以通过Aspectj注解或基于XML配置AOP。

二、AOP实现过程

1.创建Java工程

2.拷贝所需jar包

新建lib文件夹并将所需jar包拷入,并Build Path
在这里插入图片描述

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: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-4.3.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
	<context:component-scan base-package="com.jd"></context:component-scan>
	<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
</beans>

CalculatorService代码:

package com.jd.calculator;

import org.springframework.stereotype.Service;

@Service
public class CalculatorService implements ICalculatorService {

	@Override
	public int mul(int a, int b) {
		int result = a*b;
		System.out.println(this.getClass().getName()+":Result of the mul method:"+result);
		return result;
	}

	@Override
	public int div(int a, int b) {
		System.out.println(this.getClass().getName()+":The div method begins.");
		System.out.println(this.getClass().getName()+":Parameters of the div method: ["+a+","+b+"]");
		int result = a/b;
		System.out.println(this.getClass().getName()+":Result of the div method:"+result);
		System.out.println(this.getClass().getName()+":The div method ends.");
		return result;
	}
}

接口ICalculatorService代码:

package com.jd.calculator;

public interface ICalculatorService {
	public int mul(int a, int b);
	public int div(int a, int b);
}

CalculatorAspect 代码:

package com.jd.calculator;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;



@Aspect			//	切入,Spring扫描到这个注解,表明这个方法就是一个切面  
@Service		//这个注解作用是将Calculator类创建对象并保存到Spring容器
public class CalculatorAspect {
	//前置增强  放在动态代理前面的代码
	@Before("execution(int mul(int,int))")//执行哪个方法的时候(这里是之前)执行下面的方法,这里是乘法
	public void before(JoinPoint jp) {
		Object object = jp.getTarget();//得到目标对象
		Object [] args = jp.getArgs();//得到参数
		String name = jp.getSignature().getName();//得到方法名
		//前置增强的内容
		System.out.println(object.getClass().getName()+":The mul method begins.");
		System.out.println(object.getClass().getName()+":Parameters of the "+name+" method: ["+args[0]+","+args[1]+"]");
	}
	
	
	@After("execution(int mul(..))")//执行哪个方法的时候(这里是之后)执行下面的方法,这里是乘法
	public void after(JoinPoint jp) {
		Object object = jp.getTarget();//得到目标对象
		Object [] args = jp.getArgs();//得到参数
		String name = jp.getSignature().getName();//得到方法名
		//后置增强内容
		System.out.println(this.getClass().getName()+":The "+name+" method ends.");
	}
}

Test类:

package com.jd.test;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.jd.calculator.ICalculatorService;

public class Test {
	public static void main(String[] args) {
		ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");//创建IoC容器创建对象,去xml读context配置 
		ICalculatorService calculatorService = applicationContext.getBean(ICalculatorService.class);
		int result = calculatorService.mul(1, 1);
		System.out.println("-->"+result);
	}
}

三、AOP过程分析

application.xml配置文件解释

在创建好的application.xml文件中,添加了如下两行代码:

<context:component-scan base-package="com.jd"></context:component-scan>
<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>

其中第一行:

<context:component-scan base-package="com.jd"></context:component-scan>

在指定路径下扫描所有带有@Component、@Service、@Controller、@Repository注解的类,并把这些类纳入进Spring容器中。

第二行:

<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

如果创建目标对象的目标类中的方法与AspectJ切面中切入点表达式匹配,则自动为该目标对象生成动态代理对象,在本工程中,具体过程如下:
1.标签配置后,Spring就会寻找有@Aspect注解的类 将会找到CalculatorAspect类
2.找到以后开始寻找该类中所有的方法
3.获取该类中方法的注解 @Before和@After
4.获取注解括号中表达式,execution(int mul(int , int ))或者execution(int mul(… ))
5.开始检查Spring能扫描到的所有类,找到含有与表达式匹配的方法***(mul)***对应的类 ,为该类创建对象

==注意:==该代理对象默认使用JDK动态代理,当配置为
<aop:aspectj-autoproxy poxy-target-class="true"/></aop:aspectj-autoproxy>
时,则使用CGLib动态代理

当aop:aspectj-autoproxy标签内的proxy-target-class标签属为"false"时,

ICalculatorService calculatorService = applicationContext.getBean(ICalculatorService.class)

不能写成

 ICalculatorService calculatorService = applicationContext.getBean(CalculatorService.class)

这是因为,当proxy-target-class标签属性为"false"表示使用jdk生成代理对象,此时创建代理对象的代理类与创建目标对象的类之间没有继承关系,所以不能写成applicationContext.getBean(CalculatorService.class),但是由于此时创建代理对象的代理类实现了ICalculatorService接口,所以可以写成applicationContext.getBean(ICalculatorService.class);

当proxy-target-class标签属性为"true"表示使用CGLib生成代理对象,此时创建代理对象的代理类继承创建目标对象的类,所以可以写作applicationContext.getBean(CalculatorService.class)。

整个main方法执行过程

Test类中main方法:

public static void main(String[] args) {
		ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");
		ICalculatorService calculatorService = applicationContext.getBean(ICalculatorService.class);
		System.out.println(calculatorService.getClass().getName());
		int result = calculatorService.mul(1, 1);
		System.out.println("-->"+result);
	}

第一行

ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");

创建Ioc容器,创建对象,去xml读context配置,具体过程上一部分已经解释过,这里简单重述一下:
1.标签配置后,Spring就会寻找有@Aspect注解的类
2.找到以后开始寻找该类中所有的方法
3.获取该类中方法的注解
4.获取注解括号中表达式
5.开始检查Spring能扫描到的所有类,找到含有与表达式匹配的方法对应的类 ,为该类创建对象

第二行:

ICalculatorService calculatorService = applicationContext.getBean(ICalculatorService.class);

获取所创建的动态代理对象

第三行:

int result = calculatorService.mul(1, 1);

动态代理的详细过程,具体见:https://blog.csdn.net/qq_41763734/article/details/96031377

第四行:

	System.out.println("-->"+result);

打印计算结果。

运行Test类,控制台输出:

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值