JDK动态代理的原理是根据定义好的规则,用传入的接口创建一个新类,这就是为什么采用动态代理时为什么只能用接口引用指向代理,而不能用传入的类引用执行动态类。
cglib采用的是用创建一个继承实现类的子类,用asm库动态修改子类的代码来实现的,所以可以用传入的类引用执行代理类
Spring AOP
AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。Spring主要通过代理来实现AOP。
切面(Aspect):对横切关注点的抽象(类似类对对象的抽象)
连接点(JoinPoint):被拦截到的点,泛指方法。
切入点(CutPoint):对哪些连接点进行拦截的定义。
通知(Advice):在特定的连接点,AOP框架执行的动作.前置/后置/例外/最终/环绕通知。
引入(Introduction): 添加方法或字段到被通知的类。Spring允许引入新的接口到任何被通知的对象。
目标对象(Target Object): 包含连接点的对象。也被称作被通知或被代理对象。
AOP代理(AOP Proxy): AOP框架创建的对象,包含通知。在Spring中,AOP代理可以是JDK动态代理或者CGLIB代理。
织入(Weaving): 组装切面来创建一个被通知对象。这可以在编译时完成也可以在运行时完成。Spring在运行时完成织入。
示例代码:
接口类:
- package org.iti.wxl.springaop;
- public interface UserService {
- public String getUser(String userId);
- public void addUser();
- }
对接口的实现:
- package org.iti.wxl.springaop;
- public class UserServiceImpl implements UserService {
- @Override
- public String getUser(String userId) {
- System.out.println("this is getUser() method!");
- return "user";
- }
- @Override
- public void addUser() {
- System.out.println("this is addUser() method!");
- }
- }
定义切面:
- package org.iti.wxl.springaop;
- import org.aspectj.lang.ProceedingJoinPoint;
- import org.aspectj.lang.annotation.After;
- import org.aspectj.lang.annotation.AfterReturning;
- import org.aspectj.lang.annotation.AfterThrowing;
- import org.aspectj.lang.annotation.Around;
- import org.aspectj.lang.annotation.Aspect;
- import org.aspectj.lang.annotation.Before;
- import org.aspectj.lang.annotation.Pointcut;
- @Aspect
- public class MyInterceptor {
- @Pointcut("execution(* org.iti.wxl.springaop..*.*(..))")
- private void pointCutmethod(){
- }
- @Before("pointCutmethod() && args(userId)")
- public void doBefore(String userId){
- System.out.println("前置通知 " + userId);
- }
- @AfterReturning("pointCutmethod()")
- public void doAfterReturning(){
- System.out.println("后置通知");
- }
- @AfterThrowing("pointCutmethod()")
- public void doAfterException(){
- System.out.println("异常通知");
- }
- @After("pointCutmethod()")
- public void doAfter(){
- System.out.println("最终通知");
- }
- @Around("pointCutmethod()")
- public Object doAround(ProceedingJoinPoint pjp) throws Throwable{
- System.out.println("环绕开始");
- Object object = pjp.proceed();
- System.out.println("环绕结束");
- return object;
- }
- }
说明:
第一个*表示方法的返回值,这里使用通配符,只有返回值符合条件的才拦截(!void表示有返回值)。
第一个..表示com.royzhou.aop包及其子包。
倒数第二个*表示包下的所有Java类都被拦截。
最后一个*表示类的所有方法都被拦截。
(..)表示方法的参数可以任意多个,如[(java.lang.String,java.lang.Integer)表示第一个参数是String,第二个参数是int的方法才会被拦截]
配置文件:
- <?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:context="http://www.springframework.org/schema/context"
- xmlns:aop="http://www.springframework.org/schema/aop"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
- http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context-3.0.xsd
- http://www.springframework.org/schema/aop
- http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
- <!-- 使用 annotation -->
- <context:annotation-config />
- <!-- 启用aop -->
- <aop:aspectj-autoproxy proxy-target-class="true" />
- <bean id="myInterceptor" class="org.iti.wxl.springaop.MyInterceptor"/>
- <bean id="userService" class="org.iti.wxl.springaop.UserServiceImpl"/>
- </beans>
测试类:
- package org.iti.wxl.springaop;
- import org.springframework.context.ApplicationContext;
- import org.springframework.context.support.ClassPathXmlApplicationContext;
- public class SpringAOP {
- public static void main(String[] args) {
- ApplicationContext cxt = new ClassPathXmlApplicationContext("bean.xml");
- UserService userService = (UserService)cxt.getBean("userService");
- userService.getUser("user1");
- System.out.println("===========");
- userService.addUser();
- }
- }
运行结果:
- 前置通知 user1
- 环绕开始
- this is getUser() method!
- 后置通知
- 最终通知
- 环绕结束
- ===========
- 环绕开始
- this is addUser() method!
- 后置通知
- 最终通知
- 环绕结束
在项目开发中,AOP主要用来配置spring的声明式事务管理,它还可用在日志管理,性能监测等。它为程序员编程提供了一种新思路,我们可以不断去发现它的新用途。