1、普通静态代理:
代理设计模式:
代理设计模式中,一个类代表另外一个类的功能,这种类型的设计模式属于结构性设计模式。
对于被代理人来讲,这件事情是一定要去做的,但是我自己又不想做或者没有时间做,则需要找代理。
当我们想要对一个类的访问做出一些个控制,这个时候我们就要使用代理设计模式。
代理设计模式的使用场景:
西游记的案例:
猪八戒要去高老庄找高翠兰小姐,但是找到的确是孙悟空变化成的高翠兰。
这个场景可以这样理解:
先把高翠兰的外貌特征抽取出来变成一个接口,然后高翠兰本人和孙悟空两个类都去实现这个外貌的接口,当猪八戒去访问的时候,猪八戒其实访问的是
孙悟空,但是由于外貌是高翠兰的,所以他看不出来是孙悟空。在这里,高翠兰本人是被代理类,孙悟空是代理类
火车站售票点的案例:
火车站售票点帮助火车站出售火车票,场景也可以自行推倒。
下面是整个代码的案例结构(其中Image接口表示高翠兰的长相,RealImage是高翠兰本人,ProxyImage是孙悟空这个代理):
下面代码是西游记案例的实现代码:
Image,java
package com.zwz.test;
public interface Image {
public void display();
}
ProxyImage.java
package com.zwz.test;
public class ProxyImage implements Image{
private String filename;
private RealImage realImage;
public String getFilename() {
return filename;
}
public void setFilename(String filename) {
this.filename = filename;
}
public ProxyImage(String filename) {
super();
this.filename = filename;
}
@Override
public void display() {
// TODO Auto-generated method stub
//System.out.println(filename+" display");
if(realImage==null){
realImage = new RealImage( filename);
}
realImage.display();
}
}
package com.zwz.test;
public class RealImage implements Image{
private String filename;
public String getFilename() {
return filename;
}
public void setFilename(String filename) {
this.filename = filename;
}
public RealImage(String filename) {
super();
this.filename = filename;
loadFromDisk();
}
private void loadFromDisk() {
// TODO Auto-generated method stub
System.out.println(filename+" is loading");
}
@Override
public void display( ) {
// TODO Auto-generated method stub
System.out.println(filename+" display");
}
}
ProxyPatternDemo.java
package com.zwz.test;
public class ProxyPatternDemo {
public static void main(String[] args) {
Image image = new ProxyImage("gaocuilan");
image.display();
}
}
最后的输出结果如下图所示:
上面的篇幅以及代码主要介绍的 java中的静态代理,下面的代码则是介绍 动态代理,动态代理在springAOP的代码中应用较为广泛,
在面向切面(AOP)编程当中,动态代理可以理解为,想要实现一种功能,我们不让其本类去直接实现,而是去
获取到其代理类,让代理类在实现功能的前后干点坏事,spring当中 AOP的具体体现就是 前置通知、后置通知、环绕通知、异常通知这些。
2.JDK动态代理
在实现 JDK 动态代理之前,需要新建一个接口文件,让某个需要被代理的类去实现这个接口,然后待会儿jdk创建出来的代理对象也实现 InvocationHandler 这个接口,用来代理被代理的对象,完成其方法,并且可以在其方法前后增加代码.
具体实现如下:
首先先建一个接口文件:
Hello.java
public interface Hello {
public void sayHello();
}
HelloImpl.java
public class HelloImpl implements Hello{
public void sayHello() {
// TODO Auto-generated method stub
System.out.println("HelloImpl say hello!!");
}
}
实现JDK动态代理的类(需要实现 InvocationHandler接口):
JDKProxy.java
public class JDKProxy implements InvocationHandler{
//这个obj是要被jdk动态代理的对象
private Object obj;
//传入要被代理的对象
public JDKProxy(Object obj) {
super();
this.obj = obj;
}
public void before(){
System.out.println("say before!!");
}
public void after(){
System.out.println("say after!!");
}
//invoke方法 是 代理对象执行 被代理对象的方法
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
//代理方法之前干点坏事
before();
Object result = method.invoke(obj, args);
//代理方法之后干点坏事
after();
return result;
}
/*
Proxy.newProxyInstance这个方法的三个传入参数和含义如下:
参数1:传入一个 当前类的加载器
参数2:传入一个 当前类的接口文件
参数3:实现了 InvokeHandler的子类对象
*/
public T getProxy( ){
return (T)Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);
}
public static void main(String[] args) {
HelloImpl hi = new HelloImpl();
JDKProxy proxy = new JDKProxy(hi);
Hello hii = proxy.getProxy();
hii.sayHello();
}
}
3.CGLIB 动态代理
cglib的动态代理和jdk的动态代理最大的区别在于,cglib当中被代理的对象不需要实现接口,cglib直接代理其对象。
CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法(继承)
实现代码如下 CGlibProxy.java:
public class CGlibProxy implements MethodInterceptor{
public void before(){
System.out.println("before method");
}
public void after(){
System.out.println("after method");
}
public T getProxy(Classcls){
return (T)Enhancer.create(cls, this);
}
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy methodProxy) throws Throwable {
// TODO Auto-generated method stub
before();
Object result = methodProxy.invokeSuper(obj, args);
after();
return result;
}
public static void main(String[] args) {
CGlibProxy proxy = new CGlibProxy();
HelloImpl hi = proxy.getProxy(HelloImpl.class);
hi.sayHello();
}
}
在spring的代码当中jdk的动态代理和cglib的动态代理都会使用到
在spring的 DefaultAopProxyFactory.java 文件中 createAopProxy 方法代码如下:
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}