1、AOP
1.1、概念
AOP 为面向切面编程,采用动态代理实现。
1.2、优点
采用动态代理的方式,可以增强原有的目标类的方法,我们可以在目标方法执行前后分别做一些事情。
对于 aop 就可以在 5 种通知里做一些事情,比如说数据库连接的释放,日志的打印,事务的操作。
这种方式,使得不用修改原有程序,就可以增加功能,降低了耦合。
1.3、结构

2、AOP 入门案例
2.1、AOP 前
AOP 采用动态代理实现,故很有必要在看 AOP 前先看动态代理的实现。动态代理分为两种,对于有接口,有实现类的可以采用 jdk 动态代理,对于没有接口,只有实现类的,需要采用 cglib 代理。
2.1.1、依赖包
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 
 | <dependencies><dependency>
 <artifactId>org.springframework</artifactId>
 <groupId>spring-core</groupId>
 <version>3.2.7.RELEASE</version>
 </dependency>
 <dependency>
 <artifactId>org.springframework</artifactId>
 <groupId>spring-context</groupId>
 <version>3.2.7.RELEASE</version>
 </dependency>
 <dependency>
 <artifactId>org.springframework</artifactId>
 <groupId>spring-beans</groupId>
 <version>3.2.7.RELEASE</version>
 </dependency>
 <dependency>
 <artifactId>org.springframework</artifactId>
 <groupId>spring-expression</groupId>
 <version>3.2.7.RELEASE</version>
 </dependency>
 <dependency>
 <artifactId>org.springframework</artifactId>
 <groupId>spring-aop</groupId>
 <version>3.2.7.RELEASE</version>
 </dependency>
 <dependency>
 <groupId>org.aopalliance</groupId>
 <artifactId>com.springsource.org.aopalliance</artifactId>
 <version>1.0</version>
 </dependency>
 <dependency>
 <groupId>org.aspectj</groupId>
 <artifactId>aspectjweaver</artifactId>
 <version>1.6.12</version>
 </dependency>
 <dependency>
 <artifactId>commons-logging</artifactId>
 <groupId>commons-logging</groupId>
 <version>1.1</version>
 </dependency>
 
 | 
2.2、jdk 动态代理(AOP 手动方式)
jdk 动态代理中,代理类需要实现目标类的所有接口。
2.2.1、目标类:接口+实现类
接口:
| 12
 3
 4
 5
 
 | public interface UserService {public void addUser();
 public void updateUser();
 public void deleteUser();
 }
 
 | 
实现类:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | public class UserServiceImpl implements UserService {public void addUser() {
 System.out.println("addUser");
 }
 public void updateUser() {
 System.out.println("updateUser");
 }
 public void deleteUser() {
 System.out.println("deleteUser");
 }
 }
 
 | 
2.2.2、切面类:用于保存通知
| 12
 3
 4
 5
 6
 7
 8
 
 | public class MyAspect {public void before() {
 System.out.println("brfore");
 }
 public void after() {
 System.out.println("after");
 }
 }
 
 | 
2.2.3、代理类:生成代理对象
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 
 | public class MyBeanFactory {public static UserService createService() {
 
 final UserService userService = new UserServiceImpl();
 
 final MyAspect myAspect = new MyAspect();
 
 
 当前类.class.getClassLoader()
 目标类对象.getClass().getClassLoader()
 
 目标类对象.getClass().getInterfaces()
 new Class[]{接口.class}
 
 UserService proxyService = (UserService) Proxy.newProxyInstance(MyBeanFactory.class.getClassLoader(),
 userService.getClass().getInterfaces(), new InvocationHandler() {
 
 
 
 public Object invoke(Object proxy, Method method, Object[] arg2) throws Throwable {
 myAspect.before();
 Object obj = method.invoke(userService, arg2);
 myAspect.after();
 return obj;
 }
 });
 return proxyService;
 }
 }
 
 | 
2.2.4、测试类:
| 12
 3
 4
 5
 6
 7
 
 | @Testpublic void fun() {
 UserService userService = MyBeanFactory.createService();
 userService.addUser();
 userService.updateUser();
 userService.deleteUser();
 }
 
 | 
2.3、cglib 代理放式
cglib 代理适用于没有接口只有实现类的情况。cglib 是通过让代理类继承目标类,从而增强目标类的方法。
2.3.1、目标类等同于 jdk 动态代理的接口的实现类
2.3.2、切面类同上
2.3.3、测试类同上
2.3.4、代理类
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 
 | public class MyBeanFactory {public static UserServiceImpl createService() {
 
 final UserServiceImpl userService = new UserServiceImpl();
 
 final MyAspect myAspect = new MyAspect();
 
 Enhancer enhancer = new Enhancer();
 
 enhancer.setSuperclass(userService.getClass());
 
 
 
 enhancer.setCallback(new MethodInterceptor() {
 
 
 
 
 public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable {
 myAspect.before();
 
 Object obj = arg1.invoke(userService, arg2);
 
 arg3.invokeSuper(arg0, arg2);
 myAspect.after();
 return obj;
 }
 });
 
 UserServiceImpl proxyService = (UserServiceImpl) enhancer.create();
 return proxyService;
 }
 }
 
 | 
2.4、AOP 半自动代理
半自动代理采用 spring 提供的 org.springframework.aop.framework.ProxyFactoryBean 类(一个代理工厂)生成代理对象
2.4.1、目标类与 jdk 动态代理相同
2.4.2、切面类:环绕通知(此处与其他不同)
| 12
 3
 4
 5
 6
 7
 8
 
 | public class MyAspect implements MethodInterceptorpublic Object invoke(MethodInvocation arg0) throws Throwable {
 System.out.println("before");
 Object obj = arg0.proceed();
 System.out.println("after");
 return obj;
 }
 }
 
 | 
2.4.3、配置文件 beans.xml
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 
 | <?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans.xsd">
 
 <bean id="userService" class="beanfactory.UserServiceImpl"></bean>
 
 <bean id="myAspect" class="beanfactory.MyAspect"></bean>
 
 
 <bean id="proxyService" class="org.springframework.aop.framework.ProxyFactoryBean">
 
 <property name="interfaces" value="beanfactory.UserService"></property>
 
 <property name="target" ref="userService"></property>
 
 
 <property name="interceptorNames" value="myAspect"></property>
 </bean>
 </beans>
 
 | 
2.4.4、测试类
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 
 | @Testpublic void fun() {
 String xmlPath = "beanfactory/beans.xml";
 ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
 
 UserService userService = (UserService) applicationContext.getBean("proxyService");
 userService.addUser();
 userService.updateUser();
 userService.deleteUser();
 }
 
 | 
2.4.5、结果
before
addUser
after
before
updateUser
after
before
deleteUser
after
2.5、AOP 全自动代理
全自动代理仅需要在 beans.xml 中配置一下就好,使用aop:config。
spring 会自动判断使用那种代理方式,有接口时采用 jdk 方式,没有接口时采用 cglib 方式。
2.5.1、目标类与 jdk 动态代理相同
2.5.2、测试类与半自动方式相同
2.5.3、切面类
AOP 提供了 5 中通知类型,分别为,前置通知,返回通知,异常通知,最终通知,环绕通知,其中环绕通知最为强大。
除环绕通知,其他可以没有参数。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 
 | public class MyAspect {
 public void before(JoinPoint joinPoint) {
 System.out.println("before");
 }
 
 public void afterreturning(JoinPoint joinPoint, Object ret) {
 System.out.println("afterreturning" + ret);
 }
 
 public void throwable(JoinPoint joinPoint, Throwable e) {
 System.out.println("throwable" + " " + e.getMessage());
 }
 
 public void afterafter(JoinPoint joinPoint) {
 System.out.println("afterafter");
 }
 
 public Object invoke(ProceedingJoinPoint jontPoint) throws Throwable {
 System.out.println("环绕通知-------->前");
 Object obj = jontPoint.proceed();
 System.out.println("环绕通知---------->后");
 return obj;
 }
 }
 
 | 
2.5.4、配置文件 beans.xml
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 
 | <?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:aop="http://www.springframework.org/schema/aop"
 xsi:schemaLocation="http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans.xsd
 http://www.springframework.org/schema/aop
 http://www.springframework.org/schema/aop/spring-aop.xsd">
 <!-- 目标类 -->
 <bean id="userService" class="aop.UserServiceImpl"></bean>
 <!-- 切面类 -->
 <bean id="myAspect" class="aop.MyAspect"></bean>
 <!-- proxs-target-class="true":强制采用cglib方式代理 -->
 <aop:config proxy-target-class="true">
 <!-- 切入点 -->
 <aop:pointcut expression="execution(* aop.UserService.*(..))" id="myPointCut" />
 <!-- 切面 -->
 <aop:aspect ref="myAspect">
 <!-- 前置通知 -->
 <aop:before method="before" pointcut-ref="myPointCut" />
 <!-- 返回通知 -->
 <aop:after-returning method="afterreturning" returning="ret" pointcut-ref="myPointCut" />
 <!-- 环绕通知 -->
 <aop:around method="invoke" pointcut-ref="myPointCut" />
 <!-- 异常通知 -->
 <aop:after-throwing method="throwable" throwing="e" pointcut-ref="myPointCut" />
 <!-- 最终通知 -->
 <aop:after method="afterafter" pointcut-ref="myPointCut" />
 </aop:aspect>
 </aop:config>
 </beans>
 
 | 
2.5.5、结果
因为环绕通知中有 return 语句,故执行顺序和配置有关。
2.5.5.1、配置环绕通知时
before 环绕通知——–>前 addUser
afterafter 环绕通知———->后 afterreturning1
before 环绕通知——–>前 deleteUser
afterafter 环绕通知———->后 afterreturningnull
before 环绕通知——–>前 updateUser
afterafter
throwable / by zero
2.5.5.2、不配置环绕通知
before
addUser
afterreturning1
afterafter
before
deleteUser
afterreturningnull
afterafter
before
updateUser
throwable / by zero
afterafter
2.5.5.3、其他
异常通知,只有在产生异常后才会执行,此时,返回通知会被异常挡住不在执行。
返回通知可以拿到目标类方法拿到的返回值,如果没有返回值,就是 null。
环绕通知会使得最终通知提前。类似于,return 执行前,finally 块中的会先执行。
2.5.6、补充
全自动方式也可将切面做成类似于半自动的形式。
切面类:
前置通知:
| 12
 3
 4
 5
 
 | public class MyAspectBefore implements MethodBeforeAdvice {public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
 System.out.println("before");
 }
 }
 
 | 
环绕通知:
| 12
 3
 4
 5
 6
 7
 8
 
 | public class MyAspectMethod implements MethodInterceptor {public Object invoke(MethodInvocation arg0) throws Throwable {
 System.out.println("环绕前");
 Object obj = arg0.proceed();
 System.out.println("环绕后");
 return obj;
 }
 }
 
 | 
配置方式:
| 12
 3
 4
 5
 6
 7
 
 | <aop:config proxy-target-class="true">
 <aop:pointcut expression="execution(* aop2.UserService.*(..))" id="myPointCut" />
 
 <aop:advisor advice-ref="myAspectMethod" pointcut-ref="myPointCut" />
 <aop:advisor advice-ref="myAspectBefore" pointcut-ref="myPointCut" />
 </aop:config>
 
 |