1.什么是AOP编程
主要是分离业务代码与关注点代码
aop( aspect oriented programming ) 面向切面(方面)编程,是对所有对象或者是一类对象编程,核心是( 在不增加代码的基础上, 还增加新功能 )
也可以理解是面向同一种类型bean进行编程,或者是面向N多对象进行编程。
1.1 概念:
Aop编程:
关注点代码与业务代码分离!(jdk/cglib代理)
关注点:
重复执行的代码, 也叫关注点代码!
切面:
关注点代码形成的类,就叫做切面(事务,权限控制, 日志)
切入点表达式
拦截方法,给方法所在的类,生成代理对象!
Spring在初始化容器的时候,会根据切入点表达式的规则,会符合拦截规则的方法所在的类生成代理对象!
2.实现AOP编程——代理
概念:
Proxy, 表示代理! 提供了对目标对象另外的访问方式,即通过代理访问目标对象
Java中代理:
- 静态代理
- 动态代理–Jdk 代理
- Cglib 代理
2.1 静态代理
特点:
- 目标对象必须要实现接口
- 代理对象,要实现与目标对象一样的接口
缺点:
- 代理对象,需要依赖目标对象的接口!如果接口功能变化,目标对象变化,会引入代理对象的变化!
- 对每一个目标对象,都要分别写一个代理类,麻烦!(代理工厂)
代码示例:
1 2 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 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| public interface IUserDao { void save(); void find(); }
public class UserDao implements IUserDao{ @Override public void save() { System.out.println("模拟: 保存用户!"); }
@Override public void find() { System.out.println("查询"); }
}
public class UserDaoProxy implements IUserDao{ private IUserDao target = new UserDao();
@Override public void save() { System.out.println("代理操作: 开启事务..."); target.save(); System.out.println("代理操作:提交事务..."); }
@Override public void find() { target.find(); } }
public class App {
public static void main(String[] args) { IUserDao proxy = new UserDaoProxy(); proxy.save(); } }
|
2.2 动态代理
动态代理:
- 通常说的动态代理,就是指jdk代理!因为是通过jdk的api在运行时期,动态的生成代理对象的!
- 目标对象一定要实现接口, 代理对象不用实现接口!
JDK 生成代理对象的Api

参数loader :
当前目标对象使用的类加载器!
参数interfaces : **
当前目标对象实现的接口
参数 h: **
接口类型,事件处理器.
当执行目标对象方法的时候,会触发事件; 把当前执行的方法(method对象),传入事件处理器方法参数中, 这样就可以根据业务逻辑,判断是否执行目标对象方法或扩展功能!
InvocationHandler对象会直接调用自己的invoke方法,invoke方法将目标对象传入调用目标对象方法(method.invoke(target, args))
,而在本例中UserDao就是目标对象,而UserDao.save是目标方法method

代码示例:
1 2 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 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
|
public interface IUserDao { void save(); void find(); }
public class UserDao implements IUserDao{
@Override public void save() { System.out.println("模拟: 保存用户!"); }
@Override public void find() { System.out.println("查询"); } }
public class ProxyFactory {
private Object target; public ProxyFactory(Object target) { this.target = target; } public Object getProxyInstance() { Object proxy = Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String methodName = method.getName(); Object result = null; if ("find".equals(methodName)) { result = method.invoke(target, args); } else { System.out.println("开启事务..."); result = method.invoke(target, args); System.out.println("提交事务..."); } return result; } } ); return proxy; } }
public class App {
public static void main(String[] args) { IUserDao target = new UserDao(); System.out.println("目标对象:" + target.getClass()); IUserDao proxy = (IUserDao) new ProxyFactory(target).getProxyInstance(); System.out.println("代理对象: " + proxy.getClass()); proxy.save(); } }
|
2.3 CGLIB 代理
概念:
也叫”子类代理”
当目标对象没有实现接口,就不能使用jdk提供的代理,可以以子类的方式实现!
在运行时期动态在内存中构建一个子类对象的方法,从而对目标对象扩展,这种就是cglib代理!
Spring也支持cglib代理,核心包中已经包含此功能!
- JDK的动态代理有一个限制,就是使用动态代理的对象必须实现一个或多个接口。如果想代理没有实现接口的类,就可以使用CGLIB实现。
- CGLIB是一个强大的高性能的代码生成包,它可以在运行期扩展Java类与实现Java接口。它广泛的被许多AOP的框架使用,例如Spring AOP和dynaop,为他们提供方法的interception(拦截)。
- CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉
特点:
- 目标对象可以不实现接口
- 目标类不能为final, 如果为final报错
- 方法如果为final/static, 不会被代理拦截! 会直接执行目标对象方法 !
核心代码:
1 2 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 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
|
public class ProxyFactory implements MethodInterceptor{
private Object target; public ProxyFactory(Object target) { this.target = target; } public Object getProxyInstance() { Enhancer en = new Enhancer(); en.setSuperclass(target.getClass()); en.setCallback(this); return en.create(); } @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println("开启事务..."); Object result = method.invoke(target, args); System.out.println("提交事务..."); return result; } }
public class App {
public static void main(String[] args) { UserDao target = new UserDao(); System.out.println("目标对象:" + target.getClass()); UserDao proxy = (UserDao) new ProxyFactory(target).getProxyInstance(); System.out.println("代理对象: " + proxy.getClass()); proxy.save(); } }
|