一、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类,控制台输出: