《深入理解AOP编程:从基础概念到Spring实现》
AOP编程
AOP(Aspect Oriented Programing) 面向切面编程 =Spring动态代理开发
以切面为基本单位的程序开发,通过切脉你间的彼此协同,相互调用,完成程序构建
切面=切入点+额外功能
OOP(Object Oriented Programing)面向对象编程 java
以对象为基本单位的程序开发,通过对象间的彼此协同,相互调用,完成程序构建
POP(Procedure Oriented Programing)面向过程(方法、函数)编程以过程为基本单位程序开发,通过过程间的彼此协同,相互调用,完成程序构建
AOP概念
本质是Spring的动态代理开发,通过代理类为原始类增加额外功能
好处:利于原始类的维护
注意:AOP编程不可能取代OOP OOP编程的补充
AOP编程开发步骤
1.原始对象
2.额外功能
3.切入点
4.组装切面(额外功能+切入点)
名词解释
切面=切入点+额外功能
几何学
面=点+相同性质
方法+相同的功能
AOP底层实现原理
1.核心问题
1.AOP如何创建动态代理类(动态字节码技术)
2.Spring工厂如何加工创建代理对象
通过原始对象的id值,获得是代理对象
2.动态代理类的创建
2.1JDK动态代理
类加载器作用:ClassLoader
1.通过类加载器把对应类的字节码文件加载倒JVM
2.通过类加载器创建类的Class对象,进而创建这个类的对象
User--->user
User类Class对象 --->new User() -->user
如何获得类加载器:每一个类的.class文件 自动分配与之对应的ClassLoader
public class TestJDKProxy { /* 借类加载器 可以借用其它类 */ public static void main(String[] args) { //创建原始对象 UserService userService=new UserServiceImpl(); //JDK创建动态代理 InvocationHandler handler=new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("代理功能"); Object ret=method.invoke(userService,args); return ret; } }; UserService userServiceProxy=(UserService) Proxy.newProxyInstance(TestJDKProxy.class.getClassLoader(),userService.getClass().getInterfaces(),handler); userServiceProxy.register(new proxy.User("zhangsan","123456")); } }
2.2 CGlib动态代理
CGlib创建动态代理原理:父子继承关系创建代理对象,原始类作为父类,代理类作为子类,这样既可以保证二者方法一致,同时在代理类中提供新的实现(额外功能+原始方法)
package jdkProxy; import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy; import org.springframework.cglib.proxy.Proxy; import java.lang.reflect.Method; public class TestCGlib { public static void main(String[]args){ //创建原始对象 UserService userService=new UserService(); //通过cglib方式创建动态代理对象 //Proxy.newProxyInstance(); 不需要接口 Enhancer enhancer = new Enhancer(); enhancer.setClassLoader(TestCGlib.class.getClassLoader()); enhancer.setSuperclass(UserService.class);//父类是原始对象 MethodInterceptor interceptor = new MethodInterceptor() { @Override public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println("cglib 代理功能"); Object result = method.invoke(userService,args); return result; } }; enhancer.setCallback(interceptor); UserService userServiceProxy = (UserService) enhancer.create(); userServiceProxy.login("zhangsan","123456"); } }
总结
JDK动态代理 Proxy.newProxyInstance() 通过接口创建代理的实现类
Cglib动态代理 Enhancer
Spring工厂如何加工原始对象
编码
package factory;
import org.springframework.beans.factory.config.BeanPostProcessor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyBeanPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) {
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName){
InvocationHandler handler=new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("-----额外功能——-------");
Object ret=method.invoke(bean,args);
return ret;
}
};
return Proxy.newProxyInstance(ProxyBeanPostProcessor.class.getClassLoader(),bean.getClass().getInterfaces(),handler);
}
}
<bean id="userService" class="factory.UserServiceImpl"></bean>
<!--
1.实现配置BeanPostProcessor 进行加工
2.配置文件中对BeanPostProcessor配置
--> <bean id="proxyBeanPostProcessor" class="factory.ProxyBeanPostProcessor"></bean>
基于注解的AOP编程
1.基于注解的AOP编程开发步骤
- 1.原始对象
- 2.额外功能
- 3.切入点
- 4.组装切面
#通过切面类 定义了 额外功能@Around
定义了 切入点 @Around("execution *login(..)")
@Aspect 切面类
package aspect; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; @Aspect /* 1.额外功能 public class MyArround implements MethodInterceptor { public Object invoke(MethodInvocation methodInvocation) throws Throwable { Obejct ret=methodInvocation.proceed(); return ret; } } 2.切入点 <aop config <aop:pointcut id="" expression="execution(* *(..))"/> */ public class MyAspect { @Around("execution(* *(..))") public Object around(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("around"); Object ret=joinPoint.proceed(); return ret; } }
<?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 https://www.springframework.org/schema/aop/spring-aop.xsd"> <aop:aspectj-autoproxy/> <bean id="userService" class="aspect.UserServiceImpl"></bean> <!-- 1.额外功能 2.切入点 3.组装切面 --> <bean id="arround" class="aspect.MyAspect"></bean> <!-- 告知spring基于注解进行编程--> </beans>
细节
切入点复用
切入点复用:在切面类中定义一个函数,上面@Pointcut注解,通过这种方式,定义切入点表达式,后面更有利于切入点复用
public class MyAspect { @Pointcut("execution(* *(..))") public void myPointcut(){}; @Around(value = "myPointcut()") public Object around(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("around"); Object ret=joinPoint.proceed(); return ret; } @Around(value = "myPointcut()") public Object around1(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("around1"); Object ret=joinPoint.proceed(); return ret; } }
动态代理 创建方式
AOP底层实现 2种代理创建方式
1.JDK 通过实现接口 新的实现 创建代理对象
2.Cglib通过继承父类 做新的子类 创建代理对象
默认情况 AOP编程 底层应用JDK动态代理创建方式如果切换Cglib
1.基于注解AOP开发
<aop:aspectj-autoproxy proxy-target-class="true"/>2.传统AOP开发
<aop:config proxy-target-class="true"> <!-- 所有的方法 都作为切入点 加入额外功能 login register--> <aop:pointcut id="pc" expression="execution(* *(..))"/> <aop:advisor advice-ref="arround" pointcut-ref="pc"></aop:advisor> </aop:config>
AOP开发中的坑
坑:同一个业务类中,进行业务方法间的相互调用 只有最外层方法,才是加入了额外功能(内部方法,通过普通方式调用,都调用的是原始方法) 如果想让内层方法也调用代理对象方法,ApplicationContextAware获得工厂,进而获得对象
package aspect; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; public class UserServiceImpl implements UserService, ApplicationContextAware { private ApplicationContext applicationContext; @Override public void login(String username, String password) { System.out.println("login"); } @Override public void register(String username, String password) { System.out.println("register"); UserService userService = applicationContext.getBean("userService", UserService.class); userService.login("zhangsan", "123456"); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext=applicationContext; } }
AOP总结