您的位置:首页 > 编程语言 > Java开发

java 代理模式实现:java原生proxy类和增强型cglib库

2011-04-21 21:14 399 查看
大家可能都听说过spring的AOP编程,其实用java的反射机制也可以轻松实现。

我对AOP一个浅显的理解就是,当你在调用某个方法时,可以在调用之前或调用之后执行一些预前操作或预后操作,而不用更改被调用方法把预前操作或预后操作硬编码进去,你可以采用一种更灵活的方式,就是用代理模式来实现。

场景介绍:当我们在吃水果的时候,我们并不是直接拿到水果就吃,而是1.先用水洗洗水果,再2.吃水果,3.吃完后再洗洗手,擦擦嘴

操作2是我们直接想做的事,而操作1和操作3则是预前和预后操作。

怎么做呢?

用组合方法简单实现代理模式

实现1:

抽象一个Person接口,定义一个Person的实现类PersonA,再实现代理类

public interface Person {
public void eat(String fruit) ;
}
public class PersonA implements Person {
public PersonA() {
// TODO Auto-generated constructor stub
}
@Override
public void eat(String fruit) {
// TODO Auto-generated method stub
System.out.println("person A is eating:"+fruit);
}
}

public class PersonDelegate {
public PersonDelegate(Person p) {
// TODO Auto-generated constructor stub
this.p = p ;
}

public Person p = null;

public void eat(String fruit) {
// TODO Auto-generated method stub
washFruit(fruit);
p.eat(fruit);
clean();
}
private void washFruit(String fruit){
System.out.println("washing:"+fruit);
}
private void clean(){
System.out.println("washing hands");
}

public static void main(String[] args){
PersonDelegate delegate = new         PersonDelegate(new PersonA());
delegate.eat("apple");
}
}


输出结果:

washing:apple

person A is eating:apple

washing hands

用java原生java.lang.reflect.Proxy实现

实现2只适应于特定接口的代理,如果我们想实现对任何接口的代理呢。

为什么现在只提到接口呢,可能你会问,为什么不直接对具体类进行代理呢?问的好,因为java.lang.reflect.Proxy类只能对接口进行代理,对具体类的代理要放到最后才讲,所以为了由浅入深,先卖个关子。君莫急。

实现2:

public class PersonHandler implements InvocationHandler {

public PersonA p = new PersonA();
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
Object rt = null;
if(method.getName().equals("eat")){
washFruit((String)args[0]);
rt =  method.invoke(p, args);
clean();

}
return rt;
}

private void washFruit(String fruit){
System.out.println("washing:"+fruit);
}
private void clean(){
System.out.println("washing hands");
}
public static void main(String[] args) {
Person p = (Person) Proxy.newProxyInstance(
Person.class.getClassLoader(), new Class[] { Person.class },
new PersonHandler());
p.eat("apple");
}
}


输出结果:

washing:apple

person A is eating:apple

washing hands

封装实现2

有人可能会觉得,我还得再写一个handler,再调用proxy.newInstance.好麻烦啊,能不能一次性搞定。好,给你。

虽然代理的是具体类,但需要具体类实现某个接口。但已经能模拟直接代理具体类了。

如这里虽然直接代理PersonA,但还是需要Person接口。等到了实现4就可以去掉Person接口了。

我还加了点东西,至于是什么,你看看就知道了。

实现3

public class ProxyBroker implements InvocationHandler {
private Object delegate = null;
private ProxyBroker(Object delegate) {
// TODO Auto-generated constructor stub
this.delegate = delegate;
}
public static Object newProxy(Object obj) {
ProxyBroker broker = new ProxyBroker(obj);
Class[] interfaces = obj.getClass().getInterfaces();
Class inteface = null;
if (Pattern
.compile("^java[x]{0,1}")
.matcher(
obj.getClass()
.getCanonicalName()
.subSequence(
0,
obj.getClass().getCanonicalName()
.length())).find()) {
if (obj.getClass().getInterfaces().length > 0)
inteface = obj.getClass().getInterfaces()[0];
else
System.err.println("no avaliable interface implemented by :"
+ obj.getClass().getCanonicalName());
} else {
for (Class interfacc : interfaces) {
if (!Pattern
.compile("^java[x]{0,1}")
.matcher(
interfacc.getCanonicalName().subSequence(0,
interfacc.getCanonicalName().length()))
.find()) {
inteface = interfacc;
}
}
}
return Proxy.newProxyInstance(inteface.getClassLoader(),
new Class[] { inteface }, broker);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
Object obj = null ;
if(method.getName().equals("eat")){
washFruit((String)args[0]) ;
obj =  method.invoke(delegate, args);
clean();
}else
obj =  method.invoke(delegate, args);
return obj ;

}
public static void main(String[] args) {
Person p = (Person) ProxyBroker.newProxy(new PersonA());
p.eat("apple");
Comparable intg = (Comparable) ProxyBroker.newProxy(new Integer(10));
System.out.println(intg.compareTo(11));
}

private void washFruit(String fruit){
System.out.println("washing:"+fruit);
}
private void clean(){
System.out.println("washing hands");
}
}


washing:apple

person A is eating:apple

washing hands

-1 //看到这个就知道我加了什么了,我能对java.lang.Integer进行代理,但因为其实现的是Comparable<T>接口

//所以只能调用compareTo()方法

cglib实现

利器出现了,不需要你想代理的类实现莫个接口,是个类就行。所以在这里,可以去掉Person接口的定义了,不要再迷恋它了。很强大的吧

实现4

public class CglibProxyBroker implements MethodInterceptor {
private static CglibProxyBroker delegate = new CglibProxyBroker();

private CglibProxyBroker() {
// TODO Auto-generated constructor stub
}
public static  Object newInstance( Class clazz ){
try{
Enhancer e = new Enhancer();
e.setSuperclass(clazz);
e.setCallback(delegate);
return e.create();
}catch( Throwable e ){
e.printStackTrace();
throw new Error(e.getMessage());
}

}

@Override
public Object intercept(Object arg0, Method arg1, Object[] arg2,
MethodProxy arg3) throws Throwable {
// TODO Auto-generated method stub
Object obj  = null;
if(arg1.getName().equals("eat")){
washFruit((String)arg2[0]);
obj =  arg3.invokeSuper(arg0, arg2);
clean();
}else
obj = arg3.invokeSuper(arg0, arg2) ;
return obj;
}

public static void main(String[] args) {

Person p = (Person)CglibProxyBroker.newInstance(new PersonA().getClass());
p.eat("apple");

}

private void washFruit(String fruit){
System.out.println("washing:"+fruit);
}
private void clean(){
System.out.println("washing hands");
}
}


washing:apple

person A is eating:apple

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