常常有这样的业务需求,如在用户登录前加入日志记录,权限校验等。这些操作本身和用户登录并无太大关系,因此在业务层加入这些代码会显得冗余。这时就需要用到代理模式,就好像找工作,我们可以把复杂的寻找过程交给中介去完成,我们只需要关心自己的需求就可以了。同样,我们可以借助代理对象帮我们做一些前期和后期的操作。
通过代理访问目标对象。如此便于在目标实现的基础上增加额外的功能操作,前拦截,后拦截等,以满足自身的业务需求。
下面假设有在用户登录前加入日志记录的需求,分别用静态代理和动态代理实现:
1、静态代理
静态代理需要被代理对象和代理对象都实现相同的接口
//要实现的接口
package com.hncj.demo;
public interface UserService {
public void userLogin();
}
//要被代理的对象
package com.hncj.demo;
public class UserServiceImpl implements UserService{
@Override
public void userLogin() {
System.out.println("用户登录");
}
}
//代理对象
package com.hncj.demo;
public class StaticProxy implements UserService{
//被代理对象的实例
private UserService userService;
public StaticProxy(UserService userService) {
super();
this.userService = userService;
}
@Override
public void userLogin() {
logging();
userService.userLogin();
}
public void logging() {
System.out.println("====日志记录====");
}
public static void main(String[] args) {
new StaticProxy(new UserServiceImpl()).userLogin();
}
}
可以看出,静态代理模式在接口方法发生变化时,其实现类和代理对象都要进行维护,而且如果要被增强的方法过多,也会造成代码的冗余。
如下这种情况:
public void userLogin1() {
logging(); //重复的逻辑
userService.userLogin();
}
public void userLogin2() {
logging();
userService.userLogin();
}
public void userLogin3() {
logging();
userService.userLogin();
}
public void userLogin4() {
logging();
userService.userLogin();
}
。。。。。
2、动态代理(基于jdk)
在接口和被代理类不变的基础上,创建下面的类:
package com.hncj.demo2;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class DynamicProxy implements InvocationHandler{
//被代理对象的实例
private UserService userService;
public DynamicProxy(UserService userService) {
this.userService = userService;
}
//生成代理对象
public UserService createDynamicProxyObject() {
return (UserService) Proxy.newProxyInstance(userService.getClass().getClassLoader(), userService.getClass().getInterfaces(), this);
}
/*
*method:接口中提供的方法 args:方法的参数 proxy:代理对象
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if(method.getName().equals("userLogin")) {
logging();
return method.invoke(userService, args);
}
return method.invoke(userService, args);
}
public void logging() {
System.out.println("====日志记录====");
}
public static void main(String[] args) {
new DynamicProxy(new UserServiceImpl()).createDynamicProxyObject().userLogin();
}
}
这样一来,接口中再变更方法,只要在方法处理类中判断一下方法名即可,而且代理对象不要求实现接口,用起来很方便。
3、动态代理(基于spring的CGLib)
不需要接口,根据被代理对象的子类生成代理,需要spring的jar包
package com.hncj.demo3;
public class UserServiceImpl{
public void userLogin() {
System.out.println("用户登录");
}
}
package com.hncj.demo3;
import java.lang.reflect.Method;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
public class CglibProxy implements MethodInterceptor{
private UserServiceImpl userServiceImpl;
public CglibProxy(UserServiceImpl userServiceImpl) {
this.userServiceImpl = userServiceImpl;
}
public UserServiceImpl getCgliProxy() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UserServiceImpl.class);
enhancer.setCallback(this);
return (UserServiceImpl) enhancer.create();
}
@Override
public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable {
if(arg1.getName().equals("userLogin")) {
logging();
Object result = arg3.invokeSuper(arg0, arg2);
logging();
return result;
}
return arg3.invokeSuper(arg0, arg2);
}
public void logging() {
System.out.println("日志记录");
}
public static void main(String[] args) {
new CglibProxy(new UserServiceImpl()).getCgliProxy().userLogin();
}
}