设置代理方式
在我们配置AOP的时候如果不手动设置,则默认使用JDK动态代理
决定是否使用JDK代理由proxy-target-class属性决定,若值为false则使用JDK代理,true则使用CGLib代理
通过以测试可以验证:
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>
<bean id="method" class="com.jd.aop.MethodAOP"/>
<!-- 设定使用JDK动态代理 -->
<aop:config proxy-target-class="false">
<aop:pointcut expression="execution(public int com.jd.computer.service.ComputerService.*(..))" id="t"/>
<aop:aspect ref="method">
<aop:before method="before" pointcut-ref="t"/>
</aop:aspect>
</aop:config>
</beans>
Test.java
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.getClass());
applicationContext.close();
}
}
若proxy-target-class属性值为true,则测试结果如下:
可以看出是由CGLIB动态代理。
两种代理区别所在
JDK代理:JDK动态代理基于接口实现,代理类和目标类没有继承关系,代理类实现了目标类的所有接口
CGLib代理:CGLib使用继承机制,代理类继承目标类
这一点区分体现在,当通过applicationContext获取容器中的bean对象时,采用不同的代理方式,对getBean(Class<T> type)方法参数即表示要加载的Bean的类型也有所不同。
使用JDK代理时由于代理类仅实现了目标类同样的接口,和目标类没有任何关联。因此在设定Bean加载的类型时,不能使用目标类(如UserInfoService.class),因为Bean对象类型是代理类类型而不是原来的目标类。Bean加载类型可以设定为目标类所实现的接口,再通过上转型就可以获得一个接口对象(如IUserInfoService.class)。
而使用CGlib代理时由于代理类继承了目标类,因此Bean加载类型可以是目标类(如如UserInfoService.class),获取接口对象时通过两次上转型,从CGLib代理类对象上转型为目标类对象再上转型为接口对象。
测试:
当使用JDK代理:
public class Test {
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");
IComputerService computerService = applicationContext.getBean(ComputerService.class);//参数Class<T> type表示要加载的Bean的类型。如果该类型没有继承任何父类(Object类除外)和实现接口的话,那么要求该类型的bean在IOC容器中也必须是唯一的
Class clazz = computerService.getClass();
//JDK代理:代理类和目标类没有继承关系,代理类实现了目标类的所有接口
for (Class c : clazz.getInterfaces()) {
System.out.println(c.getName());
}
System.out.println("--------分割线--------");
System.out.println(clazz);
applicationContext.close();
}
}
结果抛出异常:
当使用CGLib代理:
public class Test {
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");
IComputerService computerService = applicationContext.getBean(ComputerService.class);//参数Class<T> type表示要加载的Bean的类型。如果该类型没有继承任何父类(Object类除外)和实现接口的话,那么要求该类型的bean在IOC容器中也必须是唯一的
Class clazz = computerService.getClass();
//CGLIB代理:代理类继承目标类
System.out.println(clazz.getSuperclass().getName());
System.out.println("--------分割线--------");
System.out.println(clazz);
applicationContext.close();
}
}