在利用spring执行代码获取代理类时,getBean方法中必须是接口类名,否则将会出现错误,例如
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");
IMathService mathService = applicationContext.getBean(MathService.class);
在getBean中写入的是MathService,而不是IMathService,此时控制台将会出现错误:
此时出现错误的原因是由于此时是由JDK进行代理,其中必须是接口类,否则将不能正常运行,Spring中有JDK代理和CGLib动态代理两种代理方式,两种方式所产生的代理类有着不同。
在具体的例子实现中,新建接口和实现类:
package com.jd.math;
public interface IMathService {
int add(int a,int b);
int div(int a,int b);
}
package com.jd.math;
import org.springframework.stereotype.Service;
@Service
public class MathService implements IMathService {
@Override
public int add(int a, int b) {
return a+b;
}
@Override
public int div(int a, int b) {
return a/b;
}
}
在spring中的xml文件中配置代码:
<context:component-scan base-package="com.jd"></context:component-scan>
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
用main方法对其中的获取的类名进行输出:
public class Test {
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");
IMathService mathService = applicationContext.getBean(IMathService.class);
System.out.println(mathService.getClass());
applicationContext.close();
}
}
此时获得正确的JDK代理类名
在xml中配置的代码 aop:aspectj-autoproxy</aop:aspectj-autoproxy> ,其中包含了属性:proxy-target-class=" ",在未说明的情况下,其中的默认值为false,此时将以JDK代理方式进行代理,getBean中只能是接口类,若将xml中的属性改为 <aop:aspectj-autoproxy proxy-target-class=“true”></aop:aspectj-autoproxy>,此时进行main输出:
此时输出的结果是CGLib动态代理所产生的结果,此时将getBean中的类名改为方法名MathService,依然能够输出正确的CGLib动态代理的结果。在CGLib时,进行输出代理类的父类,加入代码:
System.out.println(mathService.getClass().getSuperclass());
得到此时的输出结果:
再将xml代码中属性改为false,获得JDK代理时的代理类父类结果:
在JDK代理方式下,获取代理类的实现:
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");
IMathService mathService = applicationContext.getBean(IMathService.class);
System.out.println(mathService.getClass().getSuperclass());
Class clazz = mathService.getClass();
Class [] array = clazz.getInterfaces();
for(Class c : array) {
System.out.println(c.getName());
}
applicationContext.close();
}
此时获得输出结果:
对比可以发现,CGLib动态代理所产生的的代理类是目标类的子类,JDK动态代理产生的代理类与目标类没有继承关系;其代理类是目标类所实现的接口的实现类。所以JDK只能由接口类来创建实现,而CGLib动态代理即可由接口类,也可由目标类实现类。
代理类创建代理对象两个因素
1.xml里面需要配置代理。
2.调用切面类的方法与切面类的表达式相匹配
注解@Transationa
在事务中一个类中的方法被@transationa修饰,则spring自动为该类创建代理类及其代理对象,且创建的为JKD代理对象:
public interface IDataService {
boolean del();
}
@Service
public class DataService implements IDataService {
@Override
@Transactional
public boolean del() {
return true;
}
}
public static void main(String[] args) {
ClassPathXmlApplicationContext application = new ClassPathXmlApplicationContext("application.xml");
IDataService dataService = application.getBean(IDataService.class);
System.out.println(dataService.getClass().getName());
application.close();
}
xml文件中配置代码为:<aop:aspectj-autoproxy proxy-target-class=“false”></aop:aspectj-autoproxy>,此时结果:
若删去注解@Transationa,将得到结果: