前言
代理是什么:
对代码进行改造,最先想到修改业务逻辑。但是现在要求不改原有代码,对代码进行增强。
静态代理是什么:
一般来说,那就重写个方法呗,里面再调用原有方法,那这个就是静态代理,此方式不适合代码扩展,一个接口只能有一个代理,代理类需要创建很多。
动态代理是什么:
那如果代理方法多了,静态代理重写的方法也就多了,如果每个方法增强功能都差不多,能不能重写成一个方法呢,这就是动态代理了,Java API提供了Proxy类用于接口实现(反射方式)。如果类没有实现接口,这就需要另一种CGLIB实现代理(继承方式)。
提示:以下是本篇文章正文内容,下面案例可供参考
一、静态代理
代码如下(示例):
public class UserServiceImpl implements UserService{//业务接口实现类
@Override
public void run() {
System.out.println("实现方法");
}
public static void main(String[] args) {
//静态代理
UserServiceImpl_Static serviceImpl_static = new UserServiceImpl_Static();
serviceImpl_static.run();
}
}
interface UserService {//业务实现接口
void run();
}
class UserServiceImpl_Static implements UserService {//静态代理
private UserServiceImpl userService = new UserServiceImpl();
@Override
public void run() {
System.out.println("静态增强");
userService.run();
}
}
二、动态代理
1.Java Proxy
Proxy.newProxyInstance()会生成$Proxy代理类,代理类对象继承Proxy类,并指定了参数为InvocationHandler的构造方法。
通过配置系统属性让代理对象的class类写入到磁盘:System.setPropertie("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
也可以通过输出流方式写入到磁盘:
public static void main(String[] args) throws IOException {
//文件路径:E:\IdeaProjects\test\src\main\java\$Proxy0.class
getProxyClass("$Proxy0.class");
}
private static void getProxyClass(String fileName) throws IOException {
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(fileName, new Class[]{UserService.class}, 0);
FileOutputStream fos = new FileOutputStream("E:\\IdeaProjects\\test\\src\\main\\java\\" + fileName);
fos.write(proxyClassFile);
fos.flush();
fos.close();
}
代码如下(示例):
public class UserServiceImpl implements UserService{//业务接口实现类
@Override
public void run() {
System.out.println("实现方法");
}
public static void main(String[] args) {
//动态代理
UserServiceImpl_Dynamic userServiceImpl_dynamic = new UserServiceImpl_Dynamic();
UserService userService = (UserService)userServiceImpl_dynamic.get(new UserServiceImpl());
userService.run();
}
}
interface UserService {//业务实现接口
void run();
}
class UserServiceImpl_Dynamic implements InvocationHandler {//动态代理
private Object obj;
public Object get(Object obj) {
this.obj = obj;
return Proxy.newProxyInstance(this.obj.getClass().getClassLoader(),this.obj.getClass().getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("动态增强");
return method.invoke(obj,args);
}
}
2.CGLib
很多AOP的框架使用CGLib:Spring AOP和dynaop,Hibernate使用CGLIB来代理单端single-ended(多对一和一对一)关联。
通过System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"E:\\IdeaProjects\\test\\src\\main\\java\\cglib")输入代理类
代码如下(示例):
//所有非final修饰的方法 都可代理
public class UserServiceImpl{
public void run() {
System.out.println("run方法");
}
public static void main(String[] args) {
//输出代理类
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"E:\\IdeaProjects\\test\\src\\main\\java\\cglib");
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UserServiceImpl.class);//设置需继承的父类:被增强类
enhancer.setCallback(new UserServiceCGLib());//设置拦截器:增强方法
UserServiceImpl userService = (UserServiceImpl)enhancer.create();//获取代理对象
userService.run();//执行方法:多态调用子类方法,代理类中传入MethodInterceptor的实现类,会调用实现类intercept方法
}
}
class UserServiceCGLib implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("前置通知");
Object invokeSuper = methodProxy.invokeSuper(o, objects);
System.out.println("后置通知");
return invokeSuper;
}
}
总结
动态代理使用场景很多,如:打印日志,数据脱敏,耗时统计等等。