代理
概念
代理模式是对象的结构型模式,代码模式给某一个对象提供代理,并由代理对象控制原对象(目标对象,被代理对象)的引用。简单点说,就是通过一个工厂生成一个类的代理对象,当客户端使用的时候不直接使用目标对象,而是直接使用代理对象。代理对象相当于中介.
1 Jdk静态代理
1.1 概念
1.1.1 代理类和目标类实现相同的接口
1.1.2 代理类持有目标类的 的引用
1.2 实例
1.2.1 创建接口
public interface UserService {
public void addUser(String userId,String userName);
}
1.2.2 创建实现类
public class UserServiceImpl implements UserService {
@Override
public void addUser(String userId, String userName) {
System.out.println("UserServiceImpl addUser userId->>"+userId);
}
}
1.2.3 创建代理类
(代理类持有被代理类的引用)
public class UserServiceImplProxy implements UserService {
private UserService userService;
public UserServiceImplProxy(UserService userService){
this.userService = userService;
}
@Override
public void addUser(String userId, String userName) {
try {
System.out.println("开始执行:addUser");
userService.addUser(userId, userName);
System.out.println("addUser执行成功。");
} catch (Exception e) {
System.out.println("addUser执行失败。");
}
}
}
1.2.4 创建测试类
public class Client {
public static void main(String[] args) {
UserService userService = new UserServiceImplProxy(new UserServiceImpl());
userService.addUser("001", "centre");
}
}
1.2.5 缺点
需要为每一个目标类创建一个代理类,需要建立大量的代理类,耦合度高.违背了重复代码只写一次的原则.
2 Jdk动态代理
2.1 概念
Jdk的动态要求目标对象必须实现接口,因为它创建代理对象的时候是根据接口创建的。如果不实现接口,jdk无法给目标对象创建代理对象。被代理对象可以可以实现多个接口,创建代理时指定创建某个接口的代理对象就可以调用该接口定义的方法了
2.1.1 被代理对象必须实现接口,可以实现多个接口
2.1.2 代理对象由代理工厂生成
2.2 实例
2.2.1 创建接口Service接口和UserService接口(上面的接口)
public interface Service {
public void sayHello(String name);
}
2.2.2 创建目标对象
public class UserServiceImpl implements UserService ,Service{
@Override
public void addUser(String userId, String userName) {
System.out.println("UserServiceImpl addUser userId->>"+userId);
}
@Override
public void sayHello(String name) {
System.out.println("你好:"+name);
}
}
2.2.3 创建生成代理对象的类
public class LogHandler implements InvocationHandler {
private Object targertObject;
public Object newInstance(Object targertObject){
this.targertObject = targertObject;
Class targertClass = targertObject.getClass();
return Proxy.newProxyInstance(targertClass.getClassLoader(),
targertClass.getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("调用方法"+method.getName());
Object ret = null;
try {
ret = method.invoke(targertObject, args);
System.out.print("成功调用方法:"+method.getName()+";参数为:");
for (int i = 0; i < args.length; i++) {
System.out.println(args[i]);
}
} catch (Exception e) {
e.printStackTrace();
System.out.print("调用方法:"+method.getName()+"失败;参数为:");
for (int i = 0; i < args.length; i++) {
System.out.print(args[i]);
}
}
return ret;
}
}
2.2.4 创建测试类
public class Client {
public static void main(String[] args) {
Service Service = (Service)new LogHandler().newInstance(new UserServiceImpl());
UserService userService = (UserService)new LogHandler().newInstance(new UserServiceImpl());
userService.addUser("001", "centre");
Service.sayHello("centre");
}
}
2.2.5 缺点
jdk给目标类提供动态要求目标类必须实现接口,当一个目标类不实现接口时,jdk是无法为其提供动态代理的
3 Jdk动态代理
3.1 CGLIB动态代理
spring在给某个类提供动态代理时会自动在jdk动态代理和cglib动态代理中动态的选择。使用cglib为目标类提供动态代理:需要导入cglib.jar和asm.jar
如果出现asm中的类无法找到的异常,在java工程中是真的缺少asm.jar,而在web工程中很可能是asm.jar和spring提供的org.springframework.asm-3.0.4.RELEASE.jar包冲突。
3.1.1 CGLIB动态代理首先编写一个目标类:UserServiceImpl.java(上面的类)
3.1.2 然后为其创建一个代理工厂,用于生成目标类的代理对象:CglibProxy.java
如果一个类继承了某个类,在子类中没有一个方法,用cglib生成该子类的动态代理类中将没有一个方法。
3.1.3 编写CGLIB代理类
public class CglibProxy implements MethodInterceptor{
@Override
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
System.out.println("调用的方法是:" + method.getName());
Object ret = null;
try {
ret = proxy.invokeSuper(obj, args);
System.out.print("成功调用方法:"+method.getName()+";参数为:");
for (int i = 0; i < args.length; i++) {
System.out.print(args[i]);
}
} catch (Exception e) {
e.printStackTrace();
System.out.print("调用方法:"+method.getName()+"失败;参数为:");
for (int i = 0; i < args.length; i++) {
System.out.print(args[i]);
}
}
return ret;
}
}
3.1.4 编写测试类
public class CglibClient {
public static void main(String[] args) {
cglibUse1();
}
public static void cglibUse1(){
Enhancer enhancer = new Enhancer();
// 设置被代理的类(目标类)
enhancer.setSuperclass(UserServiceImpl.class);
//使用回调
enhancer.setCallback(new CglibProxy());
// 创造 代理 (动态扩展了UserServiceImpl类)
UserServiceImpl my = (UserServiceImpl) enhancer.create();
//my.addUser("001", "centre");
int ret = my.addOperter(15, 22);
System.out.println("返回的结果是:"+ret);
}
}
4 jdk动态和cglib动态代理比较
Jdk动态代理要求被代理的类要实现接口,而cglib不需要,cglib能根据内存中为其创建子类(代理对象)
5 个人理解
Jdk静态代理可以理解为中介(代理类)知道一切,所有的事情由中介来处理,其他的类完成自己的功能就好了.
jdk动态代理以接口作为媒介,利用反射建立起代理类和被代理类的关系.
CGLib的具体还有点没有理解,希望可以有人补充.
摘自: http://blog.csdn.net/centre10/article/details/6847828