动态代理:是使用反射和字节码的技术,在运行期创建指定接口或类的子类(动态代理)以及其实例对象的技术,
通过这个技术可以无侵入性的为代码进行增强;
Java的动态代理技术实现主要有两种方式:
1.JDK原生动态代理
2.CGLIB动态代理
JDK原生动态代理:
Proxy : Proxy是所有动态代理的父类,它提供了一个静态方法来创建动态代理的class对象和实例;
InvocationHandler :每个动态代理实例都有一个关联的InvocationHandler。 在代理实例 上调用方法
时,方法调用将被转发到InvocationHandler的invoke方法;
1 public class User { 2 private String name; 3 private int age; 4 private String address; 5 6 public User(String name, int age, String address) { 7 this.name = name; 8 this.age = age; 9 this.address = address; 10 } 11 12 public String getName() { 13 return name; 14 } 15 16 public void setName(String name) { 17 this.name = name; 18 } 19 20 public int getAge() { 21 return age; 22 } 23 24 public void setAge(int age) { 25 this.age = age; 26 } 27 28 public String getAddress() { 29 return address; 30 } 31 32 public void setAddress(String address) { 33 this.address = address; 34 } 35 36 @Override 37 public String toString() { 38 return "User{" + 39 "name='" + name + '\'' + 40 ", age=" + age + 41 ", address='" + address + '\'' + 42 '}'; 43 } 44 }
public interface UserService { void addUser(User user); } public class UserServiceImp implements UserService { @Override public final void addUser(User user) { System.out.println("用户存入数据库成功,数据为:"+user.toString()); } }
public class UserServiceInterceptor implements InvocationHandler { private Object relobj; private static Logger logger=Logger.getLogger(UserServiceInterceptor.class.getName()); public Object getRelobj() { return relobj; } public void setRelobj(Object relobj) { this.relobj = relobj; } public UserServiceInterceptor(Object relobj) { this.relobj = relobj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if(args!=null&&args.length>0&&args[0] instanceof User){ User user= (User) args[0]; if(user.getName().length()<=1){ throw new RuntimeException("用户名的长度需要大于1"); } } Object ret=method.invoke(relobj,args); logger.info("操作成功"); return ret; } }
public class Client { public static void main(String[] args) { User user=new User("lhh",10,"北京"); UserService us=new UserServiceImp(); UserServiceInterceptor usi=new UserServiceInterceptor(us); UserService proxy= (UserService) Proxy.newProxyInstance (us.getClass().getClassLoader(),us.getClass().getInterfaces(),usi); proxy.addUser(user); System.out.println(proxy.hashCode()); } }
无侵入的做到了对数据的校验
验证成功时做了日志的输出
CJLIB动态代理
CGLIB(Code Generation Library)是一个基于ASM的字节码生成库,它允许我们在运行时对字节码进行修改和动态生成。CGLIB通过继承方式实现代理;
Enhancer :来指定要代理的目标对象、实际处理代理逻辑的对象,最终通过调用create()方法得到代理对象,对这个对象所有非final方法的调用都会转发给MethodInterceptor;
MethodInterceptor :动态代理对象的方法调用都会转发到intercept方法进行增强;
public class UserServiceImpl { public void addUser(User user){ System.out.println("用户数据入库成功,数据为:"+user.toString()); } }
public class UserServiceInterceptor implements MethodInterceptor {
private static Logger logger=Logger.getLogger(UserServiceInterceptor.class.getName());
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
if(objects!=null&& objects.length>0&&objects[0] instanceof User){
User user= (User) objects[0];
if(user.getName().trim().length()<=1){
throw new RuntimeException("用户姓名输入长度需大于1");
}
}
Object ret=methodProxy.invokeSuper(o,objects);
logger.info("数据库操作成功");
return ret;
}
}
public class Client {
public static void main(String[] args) {
User user=new User("l",10,"北京");
Enhancer enhancer=new Enhancer();
enhancer.setSuperclass(UserServiceImpl.class);
enhancer.setCallback(new UserServiceInterceptor());
UserServiceImpl usi= (UserServiceImpl) enhancer.create();
usi.addUser(user);
}
}
CGLIB无法处理final方法,如果定义了final将无法对代码的增强
两者的区别
JDK原生动态代理是Java原生支持的,不需要任何外部依赖,但是它只能基于接口进行代理;
CGLIB通过继承的方式进行代理,无论目标对象有没有实现接口都可以代理,但是无法处理final的情况。
又是加深学习的一天......