静态代理:
代理类实现接口,构造方法传入实现类实例,代理类重写接口方法,加入逻辑。
public class ProxyDemo {
public static void main(String args[]){
IRequest subject = new RealSubject();
Proxy p = new Proxy(subject);
p.request();
}
}
interface IRequest{
void request();
}
class RealSubject implements IRequest{
public void request(){
System.out.println("request");
}
}
class Proxy implements IRequest{
private IRequest subject;
public Proxy(IRequest subject){
this.subject = subject;
}
public void request(){
System.out.println("proxy before");
subject.request();
System.out.println("proxy after");
}
}
代理类是在编译时就实现好的。也就是说 Java 编译完成后代理类是一个实际的 class 文件。
动态代理:
动态代理:代理类是在运行时生成的。也就是说 Java 编译完之后并没有实际的 class 文件,而是在运行时动态生成的类字节码,并加载到JVM中。动态代理类使用字节码动态生成加载技术,在运行时生成加载类。生成动态代理类的方法很多,如,JDK 自带的动态处理、CGLIB、Javassist 或者 ASM 库。JDK 的动态代理使用简单,它内置在 JDK 中,因此不需要引入第三方 Jar 包,但相对功能比较弱。
构造类实现InvocationHandler接口,重写Invoke方法,构造方法传入实现类。 相对优点:不用重写所有接口方法。但是只能对接口实现。
动态代理常被应用到以下几种情况中:
- 数据库连接以及事务管理
- 单元测试中的动态 Mock 对象
- 自定义工厂与依赖注入(DI)容器之间的适配器
- 类似 AOP 的方法拦截器
public class DynamicProxyDemo01 {
public static void main(String[] args) {
Subject realSubject = new RealSubject(); //1.创建委托对象
ProxyHandler handler = new ProxyHandler(realSubject); //2.创建调用处理器对象
Subject proxySubject = (Subject) Proxy.newProxyInstance(RealSubject.class.getClassLoader(),
RealSubject.class.getInterfaces(), handler); //3.动态生成代理对象
proxySubject.request(); //4.通过代理对象调用方法
}
}
/**
* 接口
*/
interface Subject{
void request();
}
/**
* 委托类
*/
class RealSubject implements Subject{
public void request(){
System.out.println("====RealSubject Request====");
}
}
/**
* 代理类的调用处理器
*/
class ProxyHandler implements InvocationHandler {
private Subject subject;
public ProxyHandler(Subject subject){
this.subject = subject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("====before====");
Object result = method.invoke(subject, args);
System.out.println("====after====");
return result;
}
}
public interface IDBQuery {
String request();
}
public class DBQuery implements IDBQuery {
public DBQuery() {
try {
Thread.sleep(1000);//假设数据库连接等耗时操作
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
@Override
public String request() {
return "request string";
}
}
public class DBQueryHandler implements InvocationHandler {
IDBQuery realQuery = null;//定义主题接口
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//如果第一次调用,生成真实主题
if(realQuery == null){
realQuery = new DBQuery();
}
//返回真实主题完成实际的操作
return realQuery.request();
}
public static IDBQuery createProxy(){
IDBQuery proxy = (IDBQuery) Proxy.newProxyInstance(
ClassLoader.getSystemClassLoader(), new Class[]{IDBQuery.class}, new DBQueryHandler()
);
return proxy;
}
@Test
public void test(){
IDBQuery idbQuery=createProxy();
System.out.println(idbQuery.request());
}
}
当使用者调用了代理对象所代理的接口中的方法的时候,这个调用的信息会被传递给InvocationHandler的invoke方法。在 invoke方法的参数中可以获取到代理对象、方法对应的Method对象和调用的实际参数。invoke方法的返回值被返回给使用者。这种做法实际上相 当于对方法调用进行了拦截。
代码一:
private static HelloService getHelloServiceProxy() {
HelloService helloService = new HelloServiceImpl();
InvocationHandler handler = new JavaDynamicProxy(helloService);
return (HelloService) Proxy.newProxyInstance(handler.getClass().getClassLoader(),
helloService.getClass().getInterfaces(), handler);
}
代码二:
public List getList(final List list) {
return (List) Proxy.newProxyInstance(DummyProxy.class.getClassLoader(), new Class[] { List.class },
new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("add".equals(method.getName())) {
throw new UnsupportedOperationException();
}
else {
return method.invoke(list, args);
}
}
});
}
cglib:
既可以对接口,也可以对类实现。
http://blog.csdn.net/danchu/article/details/70238002