这里往往还会使用到DI,把代理的实现类通过依赖注入的方式,传给代理工厂。
关于生成动态代理类的方式有两种:JDK和CGLIB。 CGLIB,是一个开源工具。spring 和hibernate已经广泛使用。
关于AOP的概念解释网上有很多。
附件的内容是关于JDK和CGLIB动态生成代理工厂的实例。
JDK动态代理和CGLIB字节码生成的区别?
JDK动态代理只能对实现了接口的类生成代理,而不能针对类 。
CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法,因为是继承,所以该类或方法最好不要声明成final。
例子为
@Component("SalesEmployee")
public class SalesDepartEmployee implements employee {
......
}
ApplicationContext ctx = new ClassPathXmlApplicationContext("employee.xml");
employee p=(employee)ctx.getBean("SalesEmployee");
则程序可以通过proxy-target-class="true" 来指定CGLIB)或proxy-target-class="false" 来指定 JDK proxy。
但是如果代码是这样
SalesDepartEmployee p=(SalesDepartEmployee )ctx.getBean("SalesEmployee");
则只能用CGLIB来生成代理,否则如果JDK proxy,则会出现下面的运行错误:
java.lang.ClassCastException:
com.sun.proxy.$Proxy13 cannot be cast to salesdepart.service.app.SalesDepartEmployee
- public Object createProxyObject(Object obj) {
- this.targetObject = obj;
- Enhancer enhancer = new Enhancer();
- enhancer.setSuperclass(obj.getClass());
- enhancer.setCallback(this);
- Object proxyObj = enhancer.create();
- return proxyObj;// 返回代理对象,返回的对象其实就是一个封装了“实现类”的代理类,是实现类的实例。
- }
JDK生成代码
- public Object newProxy(Object targetObject) {// 将目标对象传入进行代理
- this.targetObject = targetObject;
- return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
- targetObject.getClass().getInterfaces(), this);// 返回代理对象
- }
看上面的代码。在动太生成代理类时,传递的是实现类所所实现的接口argetObject.getClass().getInterfaces()。JDK只能对于接口进行做代理。如果换成类的话,则会抛java.lang.ClassCastException异常。
下面就来一段代码说明下:
(Spring's configuration file,这里强行使用JDK proxy,见红字配置项)
emploee.xml
--------------------------------------------------------------
<?xml version="1.0" encoding="GBK"?>
<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-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">
<!-- 指定自动搜索Bean组件、自动搜索切面类 -->
<context:component-scan base-package="salesdepart.service.app">
<context:include-filter type="annotation"
expression="org.aspectj.lang.annotation.Aspect"/>
</context:component-scan>
<!-- 启动@AspectJ支持 -->
<aop:aspectj-autoproxy proxy-target-class="false"/>
<context:annotation-config />
</beans>
employee .java
------------------------------------
package salesdepart.service.app;
public interface employee {
public void displayInfo();
}
SalesDepartEmployee.java
----------------------------------
@Component("SalesEmployee")
public class SalesDepartEmployee implements employee {
//@Autowired默认按类型装配,@Resource默认按名称装配
private String name;
//默认按类型装配
@Autowired(required=true)
private DummyDAO mydao;
public SalesDepartEmployee() {
System.out.println(" SalesDepartEmployee() called");
name=" default";
mydao=null;
}
@Override
public void displayInfo() {
System.out.println("displayInfo() called: this is Sales depart' employee "+name);
}
/**
* class specific method not provide in interface
*/
public void displayExtInfo() {
System.out.println("displayExtInfo() called ");
}
public void setName(String name) {
this.name=name;
}
public String getName() {
return name;
}
}
BeanTest.java
---------------------------------------------
package salesdepart.service.app;
import org.springframework.context.*;
import org.springframework.context.support.*;
import java.util.*;
public class BeanTest {
public static void main(String[] args) {
ApplicationContext ctx = new
ClassPathXmlApplicationContext("employee.xml");
SalesDepartEmployee p=(SalesDepartEmployee)ctx.getBean("SalesEmployee");
System.out.println("Hello: employee proxy class is "+p.getClass());
/**
* this method can work well for JDK proxy and CGLIB proxy
*/
p.displayInfo();
/**
* this method not provided in interface can work well for CGLIB proxy ONLY.
* If set proxy-target-class="false", then see the below errors:
* java.lang.ClassCastException:
* com.sun.proxy.$Proxy13 cannot be cast to salesdepart.service.app.SalesDepartEmployee
*/
p.displayExtInfo();
}
}
运行结果就是这样的
-----------------------
SalesDepartEmployee() called
Exception in thread "main" java.lang.ClassCastException: com.sun.proxy.$Proxy13 cannot be cast to salesdepart.service.app.SalesDepartEmployee
at salesdepart.service.app.BeanTest.main(BeanTest.java:10)