Java代理模式
代理(Proxy)是一种常用的设计模式。代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。目的就是在不需要修改原有的代码情况下扩展原功能。
静态代理
1.创建服务类接口
package com.zhang.proxy.staticProxy;
public interface UserInterface {
void save();
}
2.实现服务接口
package com.zhang.proxy.staticProxy;
public class UserImpl implements UserInterface{
public void save() {
System.out.println("执行User的save方法");
}
}
3.创建代理类
package com.zhang.proxy.staticProxy;
public class UserProxy implements UserInterface {
private UserImpl target;
public UserProxy(UserImpl target) {
this.target = target ;
}
public void save() {
System.out.println("开始执行代理类");
target.save();
System.out.println("结束执行代理类");
}
}
4.可以来测试啦
package com.zhang.proxy.staticProxy;
public class Test_20180319_01 {
public static void main(String[] args){
UserImpl user = new UserImpl();
UserProxy userProxy = new UserProxy(user);
userProxy.save();
}
}
静态代理总结:
可以做到不修改原服务代码的情况下对目标对象进行功能的扩展,但为们需要为每一个服务都创建一个代理类,工作量有些大,同时接口发生改变,代理类也需要改变。
jdk动态代理
在动态代理中我们只需要写一个动态处理器。JDK运行时为我们动态创建代理对象。
1.创建目标对象接口
package com.zhang.proxy.jdkProxy;
public interface UserService {
public void add();
}
2.创建目标对象实现类
package com.zhang.proxy.jdkProxy;
public class UserServiceImpl implements UserService {
public void add() {
System.out.println("执行UserServiceImpl的add方法");
}
}
3.编写jdk动态处理器
package com.zhang.proxy.jdkProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @Description : jdk动态代理
* @Author : zhangMing
* @Date : Created in 下午4:13 2018/3/19
*/
public class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(Object target){
this.target = target;
}
/**
* 执行目标对象方法
* @param proxy
* @param method
* @param args
* @return
* @throws Throwable
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("执行目标方法前");
Object result = method.invoke(target,args);
System.out.println("执行目标方法后");
return result;
}
/**
* 获取目标对象的代理对象
* @return 代理对象
*/
public Object getProxy() {
return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
this.target.getClass().getInterfaces(),this);
}
}
4.编写测试类
package com.zhang.proxy.jdkProxy;
public class Test_20180319_02 {
public static void main(String[] args){
//实例化目标对象
UserService userService = new UserServiceImpl();
//实例化Invocation
MyInvocationHandler invocationHandler = new MyInvocationHandler(userService);
//根据目标生成代理对象
UserService proxy = (UserService) invocationHandler.getProxy();
//调用代理对象方法
proxy.add();
}
}
Proxy.newProxyInstance()方法接受的三个参数:
1.当前目标对象使用的类加载器
2.制定目标对象实现的接口类型
3.指定动态处理器,执行目标对象时触发处理器的方法
jdk动态代理总结:
对比静态代理,动态代理减少了为们开发任务,同时降低了对接口的耦合度。遗憾的是只能对实现了接口的类进行代理。
cglib代理
由于Jdk动态代理只能对实现了接口的类进行代理。那么对于没有接口的类,就需要cglib了。
1.引入jar包
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2</version>
</dependency>
2.创建目标对象
package com.zhang.proxy.cglibProxy;
public class User {
public void add(){
System.out.println("执行User的add方法");
}
}
3.创建cglib代理类
package com.zhang.proxy.cglibProxy;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class UserCglib implements MethodInterceptor{
private Object target;
/**
* 创建代理对象
* @param target
* @return
*/
public Object getInstance(Object target){
this.target = target;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.target.getClass());
//回调方法
enhancer.setCallback(this);
return enhancer.create();
}
/**
* 回调方法
* @param o
* @param method
* @param objects
* @param methodProxy
* @return
* @throws Throwable
*/
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("执行目标方法之前");
methodProxy.invokeSuper(o,objects);
System.out.println("执行目标方法之后");
return null;
}
}
4.创建测试类
package com.zhang.proxy.cglibProxy;
public class Test_20180319_03 {
public static void main(String[] arg){
UserCglib userCglib = new UserCglib();
User user = (User)userCglib.getInstance(new User());
user.add();
}
}
cglib代理总结:
cglib创建的动态代理对象比JDK创建的性能更高,代价是创建时花费的时间也多的多。所以对于单例对象,采用cglib更合适。cglib采用动态创建子类的方法,对于final修饰的方法无法进行代理。
拓展Spring aop
Spring 默认采用JDK动态代理,如果要被代理的对象不是实现类,那么Spring会强制使用CGLib来实现动态代理。
<aop:config proxy-target-class="true">
<!-- 切面详细配置 -->
</aop:config>
target=true为cglib代理。默认为false