目录
一、IOC与AOP介绍
IOC
控制反转(IOC)是一种设计思想,就是将原本在程序中需要手动创建对象,现在交由Spring管理创建。举个例子,原本我们要在A类中调用B类的方法,就要直接在A中new出B类对象,然后调用B类中的方法,虽然能实现效果,不过存在一个问题,更改需求会对源代码进行修改,这是大忌。现在创建B对象就交给了Spring,在Spring中,B类对象被看成Bean对象(Spring中类就是Bean),这个Bean对象由spring容器进行创建和管理,当我们在配置文件中配置<Bean>
下的<property>
子元素(类的属性)时,Spring就会自动执行在A中B对象的setter方法(前提要有),这样的话A对象获取B对象中的方法,由主动new,变成被动等Spring创建。主动变被动,就可以理解成控制反转,通俗讲就是“你别动,我(Spring)来做就好”,主动变被动,这样就大大降低了耦合,Spring中全都用这种思想,即依赖类不由程序员实例化,而是通过Spring容器帮我们new指定实例并且将实例注入到需要该对象的类中,Spring通过DI(依赖注入)实现IOC(控制反转)。
可以看到后面讲aop时,applicationContext.xml(Spring配置)中就体现这种思想,比如applicationContext.xml注册三个bean,也就是Spring创建了这三个类。id可以理解成变量名,class就是实现类,第一个bean可以等价于UserService userService = new UserServiceImpl(); 同理,第二个等价于Log log = new Log();
以前Person类中定义age属性,并有getAge/setAge,然后创建并赋值 Person person = new Person(); person.setAge(16);
现在换成Spring的话就是<bean id="person" class="com.yx.entity.Person"><property name="age" value="16"></property></bean>
,这两个是一一对应的,id相当于变量名person,属性property会自动执行对应的setAge方法。Spring负责创建,这就是以前需主动创建,现在由Spring创建与管理,大大降低耦合,体现控制反转思想(主动变被动)。
AOP
面向切片编程(AOP—Aspect Oriented Programming)可以说是对OOP(面向对象编程)的补充和完善,面向对象就是将事物的特性和行为抽象为一个对象,如people类有身高、体重、年龄等属性,也有吃饭、睡觉等行为。把这些特性和行为封装成一个类,然后可以统一调用。面向切片也可以举个例子,比如people类有自己的属性和行为,但是有小一部分人生病要去医院看病,看病这个业务逻辑就不属于哪一个类,因为people泛指所有人,所有人不会都看病。AOP就是把医院看病这一个业务逻辑功能抽取出来,然后动态把这个功能切入到需要的方法(或行为)中,需要的才切入,这样便于减少系统的重复代码,降低模块间的耦合度。常用到AOP的就是安全校验、日志操作、事务操作等,给你先定义好,然后在想用的地方用,这样不会影响已经在服务器运行的项目,然后又能注入新功能,灵活。我们开发dao->service->controller是纵向的,这个AOP就是横向切入,如横向切入一个日志Log,打印执行过程。
Spring AOP就是基于动态代理实现的, 分为两种代理,jdk动态代理(基于接口)和cglib代理(基于类的)。如果目标对象实现了接口,就用jdk动态代理,如果未实现接口就用cglib动态代理。虽然动态代理可以解决耦合问题,但比较抽象,复杂,属于底层实现代理模式,我们这里直接用AOP,AOP做了很多封装,只要调用API即可,简化开发,但是AOP底层原理还是需要了解。
注意:动态代理底层利用了反射机制,反射包下Proxy类,如果想了解底层原理的,推荐这个视频 动态代理详解。
如果是面试,可以按上面文字答(图片上面的部分),比如面试官让你谈谈对IOC和AOP理解。
二、实现AOP的四种方式
首先,先要建一个maven项目,下面是pom.xml依赖和项目结构
Spring AOP支持五种类型的通知(先有个印象):
前置通知[Before advice]:在连接点前面执行,前置通知不会影响连接点的执行,除非此处抛出异常。
正常返回通知[After returning advice]:在连接点正常执行完成后执行,如果连接点抛出异常,则不会执行。
异常返回通知[After throwing advice]:在连接点抛出异常后执行。
返回通知[After advice]:在连接点执行完成后执行,不管是正常执行完成,还是抛出异常,都会执行返回通知中的内容。
环绕通知[Around advice]:环绕通知围绕在连接点前后,比如一个方法调用的前后。
<dependencies>
<dependency>