目录
一、环境配置
首先,创建service层方法div,及其代理类MethodAOP:
package club.affengkuang.computer.service;
import org.springframework.stereotype.Service;
//服务层
@Service
public class ComputerService implements IComputerService{
public int div(int a, int b) {
return a/b;
}
}
package club.affengkuang.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
//代理类
public class MethodAOP {
public void before(JoinPoint jp) {
Object [] args = jp.getArgs();
Signature signature = jp.getSignature();
String name = signature.getName();
System.out.println("the "+name+" method begins.");
System.out.println("the "+name+" method param ["+args[0]+","+args[1]+"]");
}
}
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"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.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
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
<context:component-scan base-package="club.affengkuang"></context:component-scan>
<bean id="ma" class="club.affengkuang.aop.MethodAOP"></bean>
<aop:config>
<!-- 定义一个aop表达式 -->
<aop:pointcut expression="execution(public int club.affengkuang.computer.service.ComputerService.*(..))" id="pc"/>
<!-- 设置一个切面类 -->
<aop:aspect ref="ma">
<aop:before method="before" pointcut-ref="pc"/>
</aop:aspect>
</aop:config>
</beans>
二、如何启动两种代理类
在如下测试类中调用div方法,并打印代理类类名,得到的该类名就是默认的JDK代理类:
package club.affengkuang.test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import club.affengkuang.computer.service.IComputerService;
public class Test {
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");
IComputerService computerService = applicationContext.getBean(IComputerService.class);
System.out.println(computerService.div(1,1));
System.out.println(computerService.getClass().getName());
applicationContext.close();
}
}
启动CGlib代理类,只需在application.xml文件中aop:config标签头部将proxy-target-class属性赋值为true即可,该属性默认值为false,也就是默认使用JDK代理类,赋值为true后使用的便是CGlib代理类:
<aop:config proxy-target-class="true">
<!-- 定义一个aop表达式 -->
<aop:pointcut expression="execution(public int club.affengkuang.computer.service.ComputerService.*(..))" id="pc"/>
<!-- 设置一个切面类 -->
<aop:aspect ref="ma">
<aop:before method="before" pointcut-ref="pc"/>
</aop:aspect>
</aop:config>
这时再调用测试类打印代理类类名,得到的便是CGlib代理类类名:
三、JDK代理类与CGlib代理类区别
JDK代理类:代理类和目标类无直接继承关系,代理类实现的是目标类实现的接口
CGlib代理类:直接继承自目标类
1.证明
如下:首先设置成JDK代理类,并在测试类中输出代理类所实现的接口,得到了目标类所实现的IComputerService接口:
package club.affengkuang.test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import club.affengkuang.computer.service.IComputerService;
public class Test {
@SuppressWarnings("rawtypes")
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");
IComputerService computerService = applicationContext.getBean(IComputerService.class);
Class clazz = computerService.getClass();
for(Class c:clazz.getInterfaces()) {
System.out.println(c);
}
applicationContext.close();
}
}
再将其设置成CGlib代理类,并在测试类中打印所继承的父类,得到了目标类:
package club.affengkuang.test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import club.affengkuang.computer.service.IComputerService;
public class Test {
@SuppressWarnings("rawtypes")
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");
IComputerService computerService = applicationContext.getBean(IComputerService.class);
Class clazz = computerService.getClass();
System.out.println(clazz.getSuperclass());
applicationContext.close();
}
}
2.影响
CGlib代理类直接继承自目标类,也就意味着在IOC容器中既可以通过目标类实现的接口获取代理类,也可以通过目标类获取代理类,将第13行getBean方法的参数改为通过目标类获取,同样可以得到代理类:
package club.affengkuang.test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import club.affengkuang.computer.service.ComputerService;
import club.affengkuang.computer.service.IComputerService;
public class Test {
@SuppressWarnings("rawtypes")
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");
IComputerService computerService = applicationContext.getBean(ComputerService.class);
System.out.println(computerService.getClass().getName());
applicationContext.close();
}
}
而JDK代理类和目标类无直接继承关系,所以只能通过接口获取代理类,将proxy-target-class属性改为false,即使用JDK代理类,再执行上述测试类,则会抛出异常: