强烈推荐一个大神的人工智能的教程:
简述
AOP是可以横向扩展功能的,能够在不修改原来代码的前提下实现功能扩展,AOP的实现原理即是动态代理,下文一步步优化介绍一下几种代理方式
为什么要使用代理
##1.什么是代理 代理即是将被代理对象进一步封装后,隐藏被代理对象,在不修改被代理对象代码的前提下完成一些额外的处理。 ##2.场景描述 有一个BookService类,其中有一个add方法,现在想在执行hello方法之前打印一句话,例如是打印”方法之前…”这几个字 “` public class BookService{ public void hello(){ System.out.println(“我是service”); } } “`
####2.1未使用代理时
代码语言:javascript
复制
public class BookService{ public void hello(){ System.out.println("方法之前..."); System.out.println("我是service"); } }
在这个功能上又来了新需求:在这个方法后打印”方法之后…”这几个字,这时候又需要修改现有的代码 缺点:
代码不利于维护
当类似的需求多了,欧博娱乐一味的修改原来的代码,工作量越来越大,而且会有很多重复的内容,每个地方都需要修改,一旦需求变了,现在不需要打印了,那全部用到的地方就需要重新修改一遍,想想都觉得有点难过呢...
违背了设计原则:开闭原则(OCP),对扩展开放,对修改关闭
违背了设计原则:单一职责(SRP),每个方法除了自己本质功能外还要考虑不断的添加其他的功能
####2.2 使用静态代理优化
①定义一个抽象接口:
代码语言:javascript
复制
public interface IBookService { public void hello(); }
②被代理类实现IBookService接口:
代码语言:javascript
复制
public class BookService implements IBookService{ public void hello(){ System.out.println("我是service"); } }
③创建一个代理类,实现共同的接口IBookService
代码语言:javascript
复制
public class Proxy implements IBookService { //依赖被代理的对象 IBookService bookService = new BookService(); //重写方法 public void hello() { System.out.println("方法之前..."); //调用被代理对象的接口 bookService.hello(); } }
优点:
符合设计原则:开放封闭原则(OCP),没有修改原来的代码,而是通过代理扩展
符合单一职责原则
缺点:
代理对象和被代理对象之前是一种强耦合,代理对象必须知道被代理对象具体的变量或方法,从而进行调用。一旦被代理对象多起来,那就需要创建多个代理,同样不好维护。 ####2.3 使用JDK提供的动态代理优化 JDK提供的动态代理有一个特点是基于接口的,也就是被代理对象必须是实现接口的,否则JDK的动态代理是无法实现代理的。使用JDK的动态代理需要创建接口,让被代理对象实现接口。 创建一个代理对象:
代码语言:javascript
复制
public class Proxy implements InvocationHandler { Object targetObject; //3.创建一个方法来生成对象,参数是要代理的对象,getInstance返回的对象是代理对象 public Object getInstance(Object o){ //3.1创建LogProxy对象 //3.2设置这个代理对象 this.targetObject = o; //3.3通过Proxy的方法创建代理对象,第一个参数是要代理对象的classLoader //第二个参数是要代理对象实现的所有接口,第三个参数是实现类的InvocationHandler对象 //此时的result就是一个代理对象,代理的是o Object result = java.lang.reflect.Proxy.newProxyInstance(o.getClass().getClassLoader(),o.getClass().getInterfaces(),this); return result; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("方法之前..."); Object invoke = method.invoke(targetObject, args); return invoke; } }
写一个测试类:
代码语言:javascript
复制
public class TestJDK { public static void main(String[] args) { IBookService instance = (IBookService) new Proxy().getInstance(new BookService()); instance.hello(); } }
执行结果:
代码语言:javascript
复制
方法之前... 我是service
总结:
JDK提供的动态代理,被代理的对象必须要有接口,这样就有一些局限性,欧博allbet当需要被代理的对象没有接口时就不能使用这种方式,然而也没有必要为了使用JDK动态代理而抽象出一些不必要的接口。
JDK提供的动态代理使用步骤如下:①被代理类实现接口 ②代理类实现InvocationHandler接口 ③通过Proxy.newProxyInstance创建代理对象 ④重写InvocationHandler接口的invoker方法,实现在不修改原来代码的前提下动态扩展 ####2.4 cglib动态代理优化 解决JDK提供的代理方式要求被代理对象必须实现接口的这个缺点,cglib提供的动态代理方式不要求被代理对象实现接口 写一个cglib代理类: ①添加maven依赖
代码语言:javascript
复制
<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.1</version> </dependency>
②代理类:
代码语言:javascript
复制
public class Proxy implements MethodInterceptor Enhancer enchancer = new Enhancer();//字节码增强器 public Object getInstance(Object o){ enchancer.setSuperclass(User.class);//设置被代理类为父类 enchancer.setCallback(new UserInterceptor());//设置回调 return enchancer.create();//创建代理实例 } public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("方法之前..."); Object object = methodProxy.invokeSuper(o,objects); return object; } }
③写一个测试类:
代码语言:javascript
复制
public class TestCglib { public static void main(String[] args) { BookService instance = (BookService) new Proxy().getInstance(new BookService()); instance.hello(); } }
总结:
被代理对象不需要实现接口
因为是继承关系,因此final修饰的方法是无法增强的,这种代理方式也是有限制的
总结
传统方式中,类与类之前的耦合性非常强,未使用代理时想要扩展,需要修改原来代码,这样就不符合设计原则,因此有了静态代理,在不修改原来代码情况下实现扩展,这样,一旦类多了就需要创建多个代理类,不利于维护,因此有了动态代理,两种动态代理各有优缺点,因此代理一次次的优化使得编码更加的灵活
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。