一、静态代理
在运行前,已经通过逻辑代码有了代理类的字节码文件,只能代理单一的服务对象,有多个服务对象的话每个对象都得创建自己的代理类
/**
* 代理接口
* @author xnn
* @date 2021-09-30 10:58
*/
public interface Subject {
void doSomeThing(String thing);
}
/**
* 真正执行任务的类
*/
public class RealSubject implements Subject {
/**
* 执行任务。
* @param thing
*/
@Override
public void doSomeThing(String thing) {
System.out.println("搞事情:"+ thing);
}
}
/**
* 代理类,实现了代理接口
* @author xnn
* @date 2021-09-30 11:02
*/
public class ProxySubject implements Subject{
/**
* 代理类持有一个委托类的对象引用
*/
private Subject delegate;
public ProxySubject(Subject delegate) {
this.delegate = delegate;
}
/**
* 将请求分派给委托类执行
*
* @param thing
*/
@Override
public void doSomeThing(String thing) {
//将请求分派给委托类处理
delegate.doSomeThing(thing);
}
}
/**
* 静态代理类工厂
* @author xnn
* @date 2021-09-30 11:02
*/
public class SubjectStaticFactory {
//调用此工厂方法获得代理对象,其并不知道返回的是代理类对象还是委托类对象。
public static Subject getInstance(){
return new ProxySubject(new RealSubject());
}
public static void main(String[] args) {
Subject proxy = SubjectStaticFactory.getInstance();
proxy.doSomeThing("我要搞事情了!");
}
}
二、动态代理
代理关系是在运行时期确定的
JDK和CGLIB动态代理的区别
- JDK动态代理只能对实现了接口的类生成代理,而不能针对类;
- CGLIB对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理,主要是对指定的类生成一个子类,覆盖其中的方法。因为是继承,所以该类或方法最好不要声明成final
2.1、JDK代理
代理类实现InvocationHandler接口,对代理对象的所有接口方法调用都会转发到InvocationHandler.invoke()方法,在invoke()方法里我们可以加入任何逻辑。对于从Object中继承的方法,JDK Proxy会把hashCode()、equals()、toString()这三个非接口方法转发给InvocationHandler,其余的Object方法则不会转发。
public interface ISayHello {
void sayHello();
}
public class SayHelloImpl implements ISayHello {
@Override
public void sayHello() {
System.out.println("This is the JDK dynamic proxy");
}
}
public class JdkProxy implements InvocationHandler {
private Object target;
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("=========="+method.getName()+"=============");
System.out.println("------JDK动态代理开始-------");
Object result = method.invoke(target, args);
System.out.println("------JDK动态代理结束-------");
return result;
}
/**
* 获取代理对象
**/
private Object newProxyInstance(Object targetObject){
// 目标对象赋值
this.target = targetObject;
// 返回代理对象
// loader,指定代理对象的类加载器;
// interfaces,代理对象需要实现的接口,可以同时指定多个接口;
// handler,方法调用的实际处理者,代理对象的方法调用都会转发到这里。
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
public static void main(String[] args) {
// 获取代理对象
ISayHello sayHello = (ISayHello) (new JdkProxy().newProxyInstance(new SayHelloImpl()));
sayHello.sayHello();
}
}
//运行结果:
//==========sayHello=============
//------JDK动态代理开始-------
//This is the JDK dynamic proxy
//------JDK动态代理结束-------
2.2、CGLib动态代理
通过CGLIB的Enhancer来指定要代理的目标对象(target.getClass())、实际处理代理逻辑的对象(this),最终通过调用create()方法得到代理对象,对这个对象所有非final方法的调用都会转发给MethodInterceptor.intercept()方法,在intercept()方法里我们可以加入任何逻辑,比如修改方法参数,加入日志功能、安全检查功能等。CGLIG中MethodInterceptor的作用跟JDK代理中的InvocationHandler很类似,都是方法调用的中转站。对于从Object中继承的方法,CGLIB代理也会进行代理,如hashCode()、equals()、toString()等,但是getClass()、wait()等方法不会,因为它是final方法,CGLIB无法代理。
2.2.1、定义实体
public class User {
/**
* user's name.
*/
private String name;
/**
* user's age.
*/
private int age;
/**
* init.
*
* @param name name
* @param age age
*/
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
2.2.2、被代理的类
对被代理的类中的方法进行增强
public class UserServiceImpl {
/**
* find user list.
*
* @return user list
*/
public List<User> findUserList() {
return Collections.singletonList(new User("pdai", 18));
}
/**
* add user
*/
public void addUser() {
// do something
}
}
2.2.3、cglib代理
实现MethodInterceptor接口,并指定代理目标类target
public class UserLogProxy implements MethodInterceptor {
/**
* 业务类对象,供代理方法中进行真正的业务方法调用
*/
private Object target;
public Object getUserLogProxy(Object target) {
//给业务对象赋值
this.target = target;
//创建加强器,用来创建动态代理类
Enhancer enhancer = new Enhancer();
//为加强器指定要代理的业务类(即:为下面生成的代理类指定父类)
enhancer.setSuperclass(this.target.getClass());
//设置回调:对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept()方法进行拦
enhancer.setCallback(this);
// 创建动态代理类对象并返回
return enhancer.create();
}
// 实现回调方法
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
// log - before method
System.out.println("[before] execute method: " + method.getName());
// call method
Object result = proxy.invokeSuper(obj, args);
// log - after method
System.out.println("[after] execute method: " + method.getName() + ", return value: " + result);
return null;
}
}
调用代理目标并执行
public class ProxyDemo {
/**
* main interface.
*
* @param args args
*/
public static void main(String[] args) {
// proxy
UserServiceImpl userService = (UserServiceImpl) new UserLogProxy().getUserLogProxy(new UserServiceImpl());
// call methods
userService.findUserList();
userService.addUser();
}
}
//运行结果:
//[before] execute method: findUserList
//[after] execute method: findUserList, return value: [User{name='pdai', age=18}]
//[before] execute method: addUser
//[after] execute method: addUser, return value: null