JDK动态代理与CGLib动态代理区别:
1、JDK动态代理基于接口实现,所以实现JDK动态代理,必须先定义接口;CGLib动态代理基于被代理类实现;
2、JDK动态代理机制是委托机制,委托hanlder调用原始实现类方法;CGLib则使用继承机制,被代理类和代理类是继承关系,所以代理类对象可以赋值给被代理类类型的变量;如果被代理类有接口,那么代理类对象也可以赋值给该接口类型的变量。
输出JDK动态代理产生的class文件,如下代码:
package com.jd.calculator;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Aspect//将该类声明为切面类
@Component//将该类对象放入IOC容器
public class CalculatorAspect {
//前置增强(又称前置通知):在目标方法开始之前执行
@Before("execution(public int com.jd.calculator.CalculatorService.*(..))")
public void before(JoinPoint joinPoint) {
Object target=joinPoint.getTarget();
String methodName = joinPoint.getSignature().getName();
Object[] params = joinPoint.getArgs();
System.out.println(target.getClass().getName()+":The "+methodName+" method begins.");
System.out.println(target.getClass().getName()+":Parameters of the "+methodName+" method: ["+params[0]+","+params[1]+"]");
}
}
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;
return result;
}
}
package com.jd.test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.jd.calculator.ICalculatorService;
public class Test {
public static void main(String[] args) {
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");//生成使用JDK创建动态代理对象的class文件。注意:该行代码必须放在代理对象产生之前
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");
ICalculatorService calculatorService =applicationContext.getBean(ICalculatorService.class);
Class<?> clazz = calculatorService.getClass();
System.out.println(clazz.getName());
applicationContext.close();
}
}
<?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.calculator"/>
<aop:aspectj-autoproxy proxy-target-class="false"/>
</beans>
输出CGLib动态代理产生的class文件,如下代码:
package com.jd.test;
import org.springframework.cglib.core.DebuggingClassWriter;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.jd.calculator.ICalculatorService;
public class Test {
public static void main(String[] args) {
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\class");//生成使用CGLib创建动态代理对象的class文件。注意:该行代码必须放在代理对象产生之前
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");
ICalculatorService calculatorService =applicationContext.getBean(ICalculatorService.class);
Class<?> clazz = calculatorService.getClass();
System.out.println(clazz.getName());
applicationContext.close();
}
}
<?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.calculator"/>
<!-- 使用CGLib生成代理对象 -->
<aop:aspectj-autoproxy proxy-target-class="true"/>
</beans>
JDK代理: 代理类和目标类没有继承关系,代理类实现了目标类所实现的接口。
CGLib代理: 代理类继承自目标类。
代理类和目标类是平行关系,代理类和目标类是父子关系。所以当是JDK代理时
IUserInfoService userInfoService = applicationContext.getBean(IUserInfoService.class);
可以获取到代理类对象
IUserInfoService userInfoService = applicationContext.getBean(UserInfoService.class);
这样则不行。
反之,如果是CGLib代理,
IUserInfoService userInfoService = applicationContext.getBean(UserInfoService.class);
依然可以获取到代理类对象。