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() {@Overridepublic 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() {@Overridepublic 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() {@Overridepublic 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;@Overridepublic void login(String username, String password) {System.out.println("login");}@Overridepublic void register(String username, String password) {System.out.println("register");UserService userService = applicationContext.getBean("userService", UserService.class);userService.login("zhangsan", "123456");}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext=applicationContext;} }
AOP总结