您的位置:首页 > 职场人生

黑马程序员_Java基础_动态代理

2015-06-08 19:33 549 查看
------- android培训java培训、期待与您交流! -------

我们先了解一下什么是代理?

生活中的代理:
代理在我们的生活中很常见 ,比如生活中的一些事情:
生活中,我们不会直接去生产产品的工厂去直接购买产品,我们会直接从代理商(超市,专卖店等)直接购买,

而不用直接去工厂购买,所以省去了不少麻烦;

程序中的代理:

要为已存在的多个具有相同接口的目标类的各个方法、增加一些系统功能,

例如:处理异常、日志、计算方法的运算时间、事务管理、等等
 怎么做?

 编写一个与目标类具有相同接口的代理类,代理类的每个方法调用目标的相同方法,并在调用方法时加上系统功能的代码

 

 如果采用工厂模式和配置文件的方式进行管理,则不需要修改客户端程序,

 在配置文件中配置是使用目标类,还是代理类,这样以后很容易切换

 比如,想要日志功能时就配置代理类,否则配置目标类,这样,增加系统功能很容易,以后运行一段时间后,又想去掉系统功能也很容易
例子1: 我们通过代理类Proxy去获取代理Collection.class中的所有方法,并打印在控制台中,并带有参数的

public class ProxyTest {
public static void main(String[] args) {
Class<?> clazz = Proxy.getProxyClass(Collection.class.getClassLoader(),
Collection.class);
System.out.println(clazz.getName());
// 输出:$Proxy0

ConstructorList(clazz);
MethodList(clazz);
}
//动态代理的所有方法
public static void MethodList(Class clazz){
System.out.println("-----------MethodList------------");
Method[] methods = clazz.getMethods();
StringBuilder sbuid = new StringBuilder();
for (Method method : methods) {
sbuid.append(method.getName());
sbuid.append("(");

Class[] clazzTypes = method.getParameterTypes();
for (Class classType : clazzTypes) {
sbuid.append(classType.getName()+",");
}
if(clazzTypes.length != 0)
sbuid.deleteCharAt(sbuid.lastIndexOf(","));
sbuid.append(")");

System.out.println(sbuid);
sbuid.delete(0, sbuid.length());
}
}

// 动态代理类的构造方法
public static  void ConstructorList(Class clazz) {
System.out.println("-----------ConstructorList------------");
Constructor[] constructors = clazz.getConstructors();
StringBuilder sbuid = new StringBuilder();
for (Constructor constructor : constructors) {
sbuid.append(constructor.getName());
sbuid.append("(");

Class[] clazzTypes = constructor.getParameterTypes();
for (Class classType : clazzTypes) {
sbuid.append(classType.getName()+",");
}
if(clazzTypes.length != 0)
sbuid.deleteCharAt(sbuid.lastIndexOf(","));
sbuid.append(")");

System.out.println(sbuid);
}
}
}

扩展知识点:

JVM可以在运行期间动态生成出类的字节码,这种动态生成的类往往被用作代理类,即动态代理类
JVM生成的动态类必须实现一个或多个接口,所有,JVM生成的动态类只能用作具有相同接口的目标类的代理
CGLIB库可以动态生成一个类的子类,一个类的子类也可以用作该类的代理,

所以,如果要为一个实现接口的类生成动态代理类,那么可以使用CGLIB库

 例子2:

动态代理类三中的实现方式:
1.获取代理.class
2.获取代理构造方法
第一种方式:创建子类实现InvocationHandler接口
                      创建代理类   Constructor.newInstance(new InvocationHandler子类对象)
第二种方式:直接创建Constructor实现时创内部类
                      Constructor.newInstance(new InvocationHandler(){
       实现方法;
})
第三种方式:使用Proxy的newProxyInstance静态方法创建代理类

下面的例子就是演示代理的实现:

public class ProxyTerst2 {
/**
* @param args
* @throws NoSuchMethodException
* @throws SecurityException
*/
public static void main(String[] args) throws Exception {
//创建动态代理类

Class<?> clazz = Proxy.getProxyClass(Collection.class.getClassLoader(),
Collection.class);
Constructor constructor = clazz.getConstructor(InvocationHandler.class);

//第一种方式:
class MyInvocationHandler1 implements InvocationHandler{
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
return null;
}
}
Collection proxy1 = (Collection) constructor
.newInstance(new MyInvocationHandler1());
System.out.println(proxy1); //输出null

//第二种方式:使用匿名内部类
Collection proxy2 = (Collection) constructor.newInstance(new InvocationHandler(){
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
return null;
}

});
System.out.println(proxy2);

//第三种方式:使用Proxy的newProxyInstance()静态方法
Collection proxy3 = (Collection) Proxy.newProxyInstance(Collection.class.getClassLoader(),
new Class[]{Collection.class},
new InvocationHandler() {
ArrayList list =new ArrayList();
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {

//开始时间
long startTime = System.currentTimeMillis();

Object revValue= method.invoke(list, args);

//结束时间
long endTime = System.currentTimeMillis();
System.out.println(method.getName()+" run of time : "+(endTime-startTime));

return revValue;
}
});

proxy3.add("123");
proxy3.add("456");
proxy3.add("789");
System.err.println(proxy3.size());
System.out.println(proxy3.getClass().getName());

}
}

  需求:自定义动态代理,在目标类的方法中添加时间计算

思想:

创建一个系统功能类的接口,并创建子类去实在

通过 使用Proxy的newProxyInstance静态方法去创建动态代理类
例子3: 

 第一部分:
public interface Advice {
public void beforMethod(Method method);
public void endMethod(Method method);
}
public class MyAdvice implements Advice {
private long startTime = 0;
@Override
public void beforMethod(Method method) {
this.startTime = System.currentTimeMillis();
}
@Override
public void endMethod(Method method) {
// TODO Auto-generated method stub
long endTime = System.currentTimeMillis();
System.out.println(method.getName()+" run of time :" +(endTime-this.startTime));
}
}


 第二部分:创建代理类
public class MyInvocationHandler implements InvocationHandler {
private Object target;
private Advice advice ;
MyInvocationHandler(Object target,Advice advice) {
this.advice = advice;
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
advice.beforMethod(method);
Object retValue = method.invoke(target, args);
advice.endMethod(method);
return retValue;
}
}

 测试部分:
public class MyInvocationHandlerTest {
/**
* @param args
*/
public static void main(String[] args) {
ArrayList list = new ArrayList();
MyAdvice myAdvice = new MyAdvice();
List proxy = (List) Proxy.newProxyInstance(list.getClass()
.getClassLoader(), list.getClass().getInterfaces(),
new MyInvocationHandler(list, myAdvice));
proxy.add("123");
proxy.add("456");
proxy.add("789");
System.out.println(proxy.size());
System.out.println(proxy.getClass().getName());
S
c33e
ystem.out.println(proxy.getClass().getClassLoader());
/*
* 输出结果:
* add run of time :0
*  add run of time :0
*   add run of time :0
*   size run of time :0
*   3
*    $Proxy0
*     null
*/

}
}

 需求:模仿Spring实现动态代理类,读取配置文件给目标类添加系统计时
 例子4:

配置文件:
 config.properties

需求:模仿Spring实现动态代理类,读取配置文件给目标类添加系统计时

例子4:
</pre><pre class="html" name="code"><span style="font: 14px/22.39px Arial; color: rgb(0, 0, 0); text-transform: none; text-indent: 0px; letter-spacing: normal; word-spacing: 0px; white-space: normal; -webkit-text-stroke-width: 0px;"><span style="color: rgb(255, 0, 0); font-weight: bold;"><span><span><span><span style="color: rgb(0, 0, 0); font-weight: normal;">配置文件:
<span> config.properties</span></span></span></span></span></span></span><div style="font: 14px/22.39px Arial; color: rgb(0, 0, 0); text-transform: none; text-indent: 0px; letter-spacing: normal; word-spacing: 0px; white-space: normal; -webkit-text-stroke-width: 0px;"> <div style="font: 14px/22.39px Arial; height: 14px; color: rgb(77, 77, 76); text-transform: none; text-indent: 0px; letter-spacing: normal; word-spacing: 0px; white-space: normal; -webkit-text-stroke-width: 0px;">#<span style="color: rgb(77, 77, 76);">xxx</span><span style="color: rgb(62, 153, 159);">=</span><span style="color: rgb(77, 77, 76);">java</span>.<span style="color: rgb(77, 77, 76);">util</span>.<span style="color: rgb(77, 77, 76);">ArrayList</span></div><div style="font: 14px/22.39px Arial; height: 14px; color: rgb(77, 77, 76); text-transform: none; text-indent: 0px; letter-spacing: normal; word-spacing: 0px; white-space: normal; -webkit-text-stroke-width: 0px;"><span style="color: rgb(77, 77, 76);">xxx</span><span style="color: rgb(62, 153, 159);">=</span><span style="color: rgb(77, 77, 76);">day15_Proxy</span>.<span style="color: rgb(77, 77, 76);">ProxyFactoryBean</span></div><div style="font: 14px/22.39px Arial; height: 14px; color: rgb(77, 77, 76); text-transform: none; text-indent: 0px; letter-spacing: normal; word-spacing: 0px; white-space: normal; -webkit-text-stroke-width: 0px;"><span style="color: rgb(77, 77, 76);">xxx</span>.<span style="color: rgb(77, 77, 76);">advice</span><span style="color: rgb(62, 153, 159);">=</span><span style="color: rgb(77, 77, 76);">day15_Proxy</span>.<span style="color: rgb(77, 77, 76);">MyAdvice</span></div><div style="font: 14px/22.39px Arial; height: 14px; color: rgb(77, 77, 76); text-transform: none; text-indent: 0px; letter-spacing: normal; word-spacing: 0px; white-space: normal; -webkit-text-stroke-width: 0px;"><span style="color: rgb(77, 77, 76);">xxx</span>.<span style="color: rgb(77, 77, 76);">target</span><span style="color: rgb(62, 153, 159);">=</span><span style="color: rgb(77, 77, 76);">java</span>.<span style="color: rgb(77, 77, 76);">util</span>.<span style="color: rgb(77, 77, 76);">ArrayList</span></div></div>

第一部分: 创建Bean工厂

public class BeanFactory {
Properties prop = new Properties();

public BeanFactory(InputStream in){
try {
prop.load(in);
} catch (IOException e) {
e.printStackTrace();
}
}

public Object getBean(String name){
String className = prop.getProperty(name);
Object bean = null;
try {
bean  = Class.forName(className).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
if(bean instanceof ProxyFactoryBean){
Object proxy = null;
ProxyFactoryBean proxyFactoryBean = (ProxyFactoryBean) bean;
try {
Object target = Class.forName(prop.getProperty(name+".target")).newInstance();
Advice advice = (Advice) Class.forName(prop.getProperty(name+".advice")).newInstance();
proxyFactoryBean.setAdvice(advice);
proxyFactoryBean.setTarget(target);
proxy = proxyFactoryBean.getProxy();
} catch (Exception e) {
e.printStackTrace();
System.out.println("创建目标失败");
}
return proxy;
}

return bean;
}
}

 第二部分:创建代理工厂

public class ProxyFactoryBean {
private Advice  advice;
private Object target;
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.beforMethod(method);
Object retValue = method.invoke(target, args);
advice.endMethod(method);
return retValue;
}
});
return proxy;
}
public Advice getAdvice() {
return advice;
}
public void setAdvice(Advice advice) {
this.advice = advice;
}
public Object getTarget() {
return target;
}
public void setTarget(Object target) {
this.target = target;
}

}

测试部分:

public class AopFrameworkTest {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
InputStream in = AopFrameworkTest.class.getResourceAsStream("config.properties");

Object bean = new BeanFactory(in).getBean("xxx");

// List list = (List)bean;
Collection list = (Collection)bean;
list.clear();
list.add("123");
list.add("456");
System.out.println(list.size());
System.out.println(bean.getClass().getName()); //输出:$Proxy0 实验成功

/*
* 输出结果:
* clear run of time :1
add run of time :0
add run of time :0
size run of time :0
2
$Proxy0
*/
}
}




内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: