--------- android培训、java培训、期待与您交流! ----------
黑马程序员---高新技术之动态代理类
(一)、代理的概念与作用
1、简单代码示例
目标类:
class X
{
void sayHello()
{
System.out.println("hello java");
}
}
代理类:
XProxy
{
void sayHello()
{
starttime;
X.sayHello();
endTime;
}
}
2、程序中的代理
(1)要为已存在的多个具有相同接口的目标类的各个方法增加一系列的系统功能,例如,异常处理,日志、计算方法等的运行时间、事务管理等等,你如何做?
(2)编写一个与目标类具有相同接口的代理类,代理类的每个方法调用目标类的相同方法,并在调用方法时加上系统功能的代码。
(3)如果采用工厂模式和配置文件的方式进行管理,则不需要修改客户端程序,在配置文件中配置是使用目标类还是代理类,这样以后很容易切换。譬如,想要日志功能时就配置代理类,否则配置目标类,这样增加系统功能很容易。以后运行一段时间后,又想去掉系统功能也很容易。
3、代理分为两种:静态代理和动态代理。
<AOP>
1.系统中存在交叉业务,一个交叉业务就是要切入到系统中的一个方法。
2.交叉业务的房产问题即为面向方面的编程(AOP,Aspect oriented program),AOP的目标就是要
使交叉业务模块化,可以采用将切面代码移动到原始方法的周围,这与直接在方法中编程切面代码的运行效果是一样的。
3.使用代理技术正好可以解决这种问题,代理是实现AOP功能的核心和关键技术。
( 二)、动态代理技术(JVM动态代理和CGLIB库动态代理)
1.要为系统中的各种接口的类增加代理功能,那将需要太多的代理类,全部采用静态代理方式,将是一件非常麻烦的事情。(引出动态代理)
2.JVM可以在运行期动态生成出类的字节码,这种动态生成的类往往被用作代理类 ,即动态代理类。
3.JVM生成的动态类必须具有一个或多个接口,所以,JVM生成的动态类(Proxy)只能用作具有相同接口的目标类的代理。
4.CGLIB库(一个开源库)可以动态生成一个类的子类,一个类的子类也可以用作该类的代理,所以,如果要为一个没有实现接口的类生成动态代理类,可以使用CGLIB库。
5.代理类的各个方法中通除了要调用目标的相应方法和对外返回目标返回的结果外,还可以在代理方法中的如下四个位置加上系统功能代码:
(1).在调用目标方法之前
(2).在调用目标方法之后
(3)在调用目标方法之前或之后
(4)在处理目标方法异常的catch块中。
6.创建JVM动态代理方法:
方法一:获取动态类字节码(Class)--->用字节码获取Constructor---->用Constructor创建动态类实例
// a.使用Proxy获取动态类字节码(以Collection为例)
Class clazzProxy1 = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);
System.out.println(clazzProxy1.getName());
// 打印clazzProxy1的所有构造方法和成员方法。
System.out.println("----begin constructors list-------");
/*
* $Proxy0
* $Proxy0(InvocationHandler ,int)
*/
printConstructors(clazzProxy1);
System.out.println("----begin methods list-------");
printMethods(clazzProxy1);<SPAN style="FONT-SIZE: 14px"> </SPAN>
public static void printMethods(Class clazzProxy1) {
Method[] methods = clazzProxy1.getMethods();
for(Method method:methods){
String name = method.getName();
StringBuilder sBuilder = new StringBuilder(name);
sBuilder.append("(");
Class[] clazzParams = method.getParameterTypes();
for(Class clazzParam:clazzParams){
sBuilder.append(clazzParam.getName()).append(",");
}
if(clazzParams!=null &&clazzParams.length!=0)
sBuilder.deleteCharAt(sBuilder.length()-1);
sBuilder.append(")");
System.out.println(sBuilder);
}
}
public static void printConstructors(Class clazzProxy1) {
Constructor[] constructors=clazzProxy1.getConstructors();
for(Constructor constructor:constructors){
String name = constructor.getName();
StringBuilder sBuilder = new StringBuilder(name);
sBuilder.append("(");
Class[] clazzParams = constructor.getParameterTypes();
for(Class clazzParam:clazzParams){
sBuilder.append(clazzParam.getName()).append(",");
}
if(clazzParams!=null &&clazzParams.length!=0)
sBuilder.deleteCharAt(sBuilder.length()-1);
sBuilder.append(")");
System.out.println(sBuilder);
}
// b.获取Constructor
Constructor constructor =clazzProxy1.getConstructor(InvocationHandler.class);
// c.用Constructor创建代理类实例:因为需要用到InvocationHandler接口类型的参数,可以先定义一个内部实现类,也可以直接用匿名内部类在参数列表上实现接口。
class MyInvocationHandler1 implements InvocationHandler{
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
return null;
}
}
Collection proxy1 = (Collection)constructor.newInstance(new MyInvocationHandler1());
System.out.println(proxy1.toString());
Collection proxy2 = (Collection)constructor.newInstance(new InvocationHandler(){
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
return null;
}
});
此时,proxy1的打印值为null,调用其无返回值的方法没有报错,调用其有返回值的方法则报空指针异常,因为它总是调用InvocationHandler的invoke方法,而这个方法此时总是返回null
方法二:直接用Proxy的静态方法newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
Collection proxy3=(Collection)Proxy.newProxyInstance(
Collection.class.getClassLoader(),
new Class[]{Collection.class},
new InvocationHandler(){
ArrayList target= new ArrayList();
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
long startTime = System.currentTimeMillis();
Object retVal = method.invoke(target, args);
long endTime = System.currentTimeMillis();
System.out.println(method.getName()+" running time:"+(endTime - startTime));
return retVal;
}
});
proxy3.add("123");
proxy3.add("453");
proxy3.add("789");
System.out.println(proxy3.size());
7、猜想分析动态生成的类的内部代码
class Proxy${
add(Object obj){
return handler.invoke(Object proxy, Method method, Object[] args);
}
}
int size()
{
return handler.invoke(this,this.getClass().getMethod("size"),null);
}
(三)将动态生成的类成为目标的代理
动态代理类的骨架用Proxy.newProxyInstance()方法就能生成,执行要再传入两个参数:要代理的目标target和增加的系统功能的封装对象(advice),就能让动态生成的类成为目标的代理啦。
//1.建立增加的系统功能封装类
import java.lang.reflect.Method;
public interface Advice {
void beforeMethod(Method method);
void afterMethod(Method method);
}
import java.lang.reflect.Method;
public class MyAdvice implements Advice {
long startTime=0;
@Override
public void beforeMethod(Method method) {
// TODO Auto-generated method stub
System.out.println("方法开始啦");
startTime = System.currentTimeMillis();
}
@Override
public void afterMethod(Method method) {
// TODO Auto-generated method stub
System.out.println("方法结束啦");
long endTime = System.currentTimeMillis();
System.out.println(method.getName()+" running time:"+(endTime - startTime));
}
}
//2.建立目标:(以Collection为例)
final ArrayList target = new ArrayList();
//3.成为目标的代理
public static Object getProxy(final Object target,final Advice advice) {
Object proxy3 =Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),//注意,这里参数是Class数组
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
advice.beforeMethod(method);
Object retVal = method.invoke(target, args);
advice.afterMethod(method);
// return method.invoke(proxy, args);//这就变成了死循环。
return retVal;
}
});
return proxy3;
}
(四)实现AOP功能的封装和配置
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import cn.itcast.day3.Advice;
public class ProxyFactoryBean {
private Object target;
private Advice advice;
public Object getTarget() {
return target;
}
public void setTarget(Object target) {
this.target = target;
}
public Advice getAdvice() {
return advice;
}
public void setAdvice(Advice advice) {
this.advice = advice;
}
public Object getProxy() {
Object proxy =Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
advice.beforeMethod(method);
Object retVal = method.invoke(target, args);
advice.afterMethod(method);
return retVal;
}
});
return proxy;
}
}
//2.BeanFacotry代码:
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import cn.itcast.day3.Advice;
public class BeanFactory {
Properties prop =new Properties();
public BeanFactory(InputStream inStream){
try {
prop.load(inStream);
} catch (IOException e) {
e.printStackTrace();
}
}
public Object getBean(String name){
String className = prop.getProperty(name);
Class clazz=null;
Object bean=null;
try {
clazz = Class.forName(className);
bean = clazz.newInstance();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(bean instanceof ProxyFactoryBean){
Object proxy = null;
try {
ProxyFactoryBean proxyFactoryBean = (ProxyFactoryBean)bean;
Advice advice = (Advice) Class.forName(prop.getProperty(className+".advice")).newInstance();
Object target =Class.forName(prop.getProperty(className+".target")).newInstance();
proxyFactoryBean.setAdvice(advice);
proxyFactoryBean.setTarget(target);
proxy = proxyFactoryBean.getProxy();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return proxy;
}else{
return bean;
}
}
}
//3.配置文件内容:
xxx=java.util.ArrayList
#xxx=cn.itcast.day3.aopframework.ProxyFactoryBean
xxx.advice=cn.itcast.day3.MyAdvice
xxx.target=java.util.ArrayList
//4.框架测试类:
import java.io.InputStream;
public class AopFrameworkTest {
public static void main(String[] args) {
InputStream ips =AopFrameworkTest.class.getResourceAsStream("config.properties");
BeanFactory beanFactory = new BeanFactory(ips);
Object bean =beanFactory.getBean("xxx");
System.out.println(bean.getClass().getName());
}
}