关于AOP思想,建议你看看这份五年开发总结的笔记,写的太详细了
前言
OOP(Object Oriented Programing)面向对象编程
以对象为基本单位进行程序开发,通过对象间的彼此协同,相互协调,完成程序的构建
POP(Producer Oriented Programing)面向过程(方法,函数)编程
以过程为基本单位的程序开发,通过彼此间协同,相互调用,完成程序的构建
静态代理存在的问题
//实现相同的接口 public class UserServiceProxy implements UserService { //创建原始对象 private UserServiceImpl userService = new UserServiceImpl(); public void register(User user) { //实现额外功能 System.out.println("-------------------"); userService.register(user); } public boolean login(String name, String password) { System.out.println("____________________"); return userService.login(name,password); } }
每一个原始类都会手工编写一个代理类
- 静态类文件数目过多,不利于项目管理
- 代码可维护性差
概述
上图展示了一个被划分的典型应用,每个模块的核心功能都是为特定业务领域提供服务,但是这些模块都需要类似的辅助功能,例如安全和事务管理。
如果要重用通用功能的话,最常见的面向对象技术是继承或者委托。但是,如果在整个应用中都使用相同的基类,继承往往会导致一个脆弱的对象体系,而使用委托可能需要对委托对象进行复杂的调用。
切面提供了取代继承和委托的另一种可选方案,而且在很多场景下更清晰简洁,在使用面向切面编程时,我们仍然在一个地方定义通用功能,但是可以通过声明的方式定义这个功能要以何种方式在何处应用,而无需修改受影响的类,横切关注点模块化为特殊的类,这些类被称为切面(aspect)。这样做有两个好处:首先,现在每个关注点都集中在一个地方,而不是分散到多处代码;其次,服务模块更简洁,因为它们只包含主要关注点(或者核心功能)的代码,而次要关注点的代码被移转到切面中了。
AOP不可能取代 OOP,它只是OOP的有意补充
Spring中的AOP
AOP:本质上就是 Spring动态代理开发,有益于原始类的维护
Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理。JDK动态代理通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口。JDK动态代理的核心是InvocationHandler接口和Proxy类。
如果目标类没有实现接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成某个类的子类,注意,CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的,诸如private的方法也是不可以作为切面的。
JDK动态代理的实现
代理创建三要素:1 原始对象 2 额外功能 3 代理对象实现相同的接口
JDK动态代理的核心是InvocationHandler接口和Proxy类。
public static void main(String[] args) { //创建原始对象 UserService userService = new UserServiceImpl(); //JDK创建动态代理 Proxy.newProxyInstance(ClassLoader ,interfaces, invocationHandler) }
public interface InvocationHandler { //用于书写额外功能 额外功能:原始方法执行前后 抛出异常 // 参数:Proxy 忽略掉,表示的是代理对象 //method 额外功能所增加给的那个原始方法 //Object[] args 原始方法的参数 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; }
interfaces:原始对象所实现的接口
userService.getClass().getInterfaces()
类加载器的作用:
- 通过类加载器把对应类的字节码加载到JVM中
- 通过类加载器创建class对象,进而创建这个类的对象
如何获得类加载器:每个类的.class文件 自动分配与之对应的ClassLoder
在动态代理创建的过程中,需要ClassLoader创建代理类的Class对象,可是动态代理类没有对应的.class文件,JVM也不会为其分配ClassLoader,但是又需要怎么办?(借用一个ClossLoader)
ClassLoader:完成代理类的创建
创建代理类的class对象,进而完成代理类的创建
//注意:类加载器是借用来的 可以随表找一个借用 // 在JDK8.0之前 内部变量访问外部变量需要加final public class JDKProxy { public static void main(String[] args) { final UserService userService = new UserServiceImpl(); InvocationHandler handler = new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("-----login-------"); //原方法运行 Object obj = method.invoke(userService, args); return obj; } }; UserService service = (UserService) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), userService.getClass().getInterfaces(), handler); service.login("gewei","hello"); service.register(new User()); } }
CGlib动态代理的实现
对于一些没有实现接口的方法
public class UserServiceImpl(){ login(); register(); }
代理类 继承你要代理的类
public clss Proxy extends UserServiceImpl(){ login(){ 额外功能 super.login(); } }
public class TestCglib { public static void main(final String[] args) { //创建原始对象 final UserService userService = new UserService(); /* 通过cglib方式创建动态代理对象 Proxy.newProxyInstance(ClassLoader ,interfaces, invocationHandler) cglib同样也需要做这些: enhancer.setClassLoader(); enhancer.setSuperclass(); enhancer.setCallback(); -->MethodInterceptor(cglib包下) */ Enhancer enhancer = new Enhancer(); enhancer.setClassLoader(TestCglib.class.getClassLoader()); enhancer.setSuperclass(userService.getClass()); MethodInterceptor interceptor = new MethodInterceptor() { //等同于 InvocationHandler -- invoke public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("hello world"); Object invoke = method.invoke(userService, args); return invoke; } }; enhancer.setCallback(interceptor); UserService userServiceProxy = (UserService) enhancer.create(); userServiceProxy.login(); userServiceProxy.register(); } }
Spring中基于AspectJ注解的AOP编程
环境搭建
<!-- 1.配置扫描的基包 --> <context:component-scan base-package="com.itheima"/> <bean id="Aspectj" class="cn.gewei.factory.Aspectj"></bean> //打开注解开发 <aop:aspectj-autoproxy/>
环绕通知
/** * 次要的业务:切面类 */ @Component //把这个类加到Spring容器中 @Aspect //这个类是切面类 public class LogAspect { @Pointcut("execution(* com.itheima.service..*.*(..))") //切面表达式,这是一个空方法,作用:创建切面表达式的 public void pt() { } /** * 环绕通知 */ @Around("pt()") public Object around(ProceedingJoinPoint joinPoint) { Object result = null; try { System.out.println("前置通知"); //调用目标方法 result = joinPoint.proceed(); System.out.println("后置通知"); } catch (Throwable throwable) { throwable.printStackTrace(); System.out.println("异常通知"); } finally { System.out.println("最终通知"); } //返回方法的返回值 return result; } }
前置,后置,异常,最终通知
/** * 次要的业务:切面类 */ @Component //把这个类加到Spring容器中 @Aspect //这个类是切面类 public class LogAspect { @Pointcut("execution(* com.itheima.service..*.*(..))") //切面表达式,这是一个空方法,作用:创建切面表达式的 public void pt() { } @Before("pt()") public void before() { System.out.println("前置通知"); } @AfterReturning("pt()") public void afterReturn() { System.out.println("后置通知"); } @AfterThrowing("pt()") public void afterThrowing() { System.out.println("异常通知"); } @After("pt()") public void after() { System.out.println("最终通知"); } }
切入点复用
@Pointcut("execution(* *(..))") public void pointcut(){} @Around(value = "pointcut()")
默认情况下Spring底层是JDK动态代理实现的
//将proxy-target-class设为true就是基于Cglib的开发模式 <aop:aspectj-autoproxy proxy-target-class="true"/>
小结
AOP是面向对象编程的一个强大补充。通过Spring的动态代理,我们现在可以把之前分散在应用各处的行为放入可重用的模块中。我们显示地声明在何处如何应用该行为。这有效减少了代码冗余,并让我们的类关注自身的主要功能。
AOP编程概念(Spring动态代理开发),通过代理类为原始类增加额外的功能,好处:利于原始类的维护。
最后
大家看完有什么不懂的可以在下方留言讨论,也可以关注我私信问我,我看到后都会回答的。也欢迎大家关注我的公众号:前程有光,马上金九银十跳槽面试季,整理了1000多道将近500多页pdf文档的Java面试题资料放在里面,助你圆梦BAT!文章都会在里面更新,整理的资料也会放在里面。谢谢你的观看,觉得文章对你有帮助的话记得关注我点个赞支持一下!
- 安卓开发笔记——关于Handler的一些总结(上)
- 关于java初学的一些笔记总结(收集+总结)与大家分享,关于自学java,有好的建议可以回帖。
- IOS开发笔记之二十二——关于导航栏与状态栏的操作总结
- Spring5系列完整学习笔记以及相关代码(含Spring基本配置,IoC,AOP思想,依赖注入,注解开发Spring,静态/动态代理模式,MyBatis整合以及相关代码案例)
- 据说是iOS开发一年总结的笔记,有空看看
- 吴恩达机器学习之总结:总结和致谢(详细笔记,建议收藏,已有专栏)
- 关于java初学的一些笔记总结(收集+总结)与大家分享,关于自学java,有好的建议可以回帖。
- 关于AOP思想的学习笔记
- 软件开发重要思想的总结
- 关于myeclipse+freemarker框架开发中的一些总结
- 软件开发重要思想的总结
- 关于AOP的学习过程简单总结
- 给网站开发人员关于项目开发的一些建议
- 关于游戏开发的一些总结
- 关于三层结构的一点使用心得与开发建议
- 移动项目开发笔记(总结MasterPage中的资源文件引用路径)
- 关于struts2,mysql,hibernate的开发环境下的中文显示为“问号”的问题总结
- 关于XNA开发游戏的一些建议
- iOS开发笔记(六)网络编程总结
- 【Android2D游戏开发十五】关于Android 游戏开发中 OnTouchEvent() 触屏事件的性能优化笔记!