当前位置: 首页 > news >正文

广州网站制台州网站外包

广州网站制,台州网站外包,网站开发 数字证书,星空传媒苏清歌孟若羽目录 1. AOP的演化过程 1. 代理模式 2. 动态代理 2.1 JDK动态代理 2.2 Cglib动态代理 3. Spring模式 3.1 ProxyFactory 3.2 ProxyFactoryBean 3.3 AbstractAutoProxyCreator 2. Spring AOP抽象 1. 核心术语 1.1 连接点(JoinPoint) 1.2 切点(Pointcut) 1.3 增强(Ad… 目录 1. AOP的演化过程 1. 代理模式 2. 动态代理 2.1 JDK动态代理 2.2 Cglib动态代理 3. Spring模式 3.1 ProxyFactory 3.2 ProxyFactoryBean 3.3 AbstractAutoProxyCreator 2. Spring AOP抽象 1. 核心术语 1.1 连接点(JoinPoint) 1.2 切点(Pointcut) 1.3 增强(Advice) 1.4 切面(Aspect) 1.5 目标对象(Target) 1.6 代理对象(Proxy) 2. 核心组件 2.1 AutoProxyCreator工作原理 2.2 EnableAspectJAutoProxy工作原理 3. Spring AOP案例 1. AOP的演化过程 编程中我们经常会遇到这样的场景有一段通用逻辑横跨多个业务不能用继承来解决比如方法耗时、数据库事务、通用日志等等。一个典型的DAO方法调用分为下面3个步骤: 每一次都手工的开启和提交事务即显得啰嗦又影响业务的可读性。AOP就十分擅长解决这类问题它把开启和提交事务的逻辑抽取到Advice当中在任务DAO上复用。那么AOP到底是怎么实现的呢 1. 代理模式 熟悉设计模式的人这时候会想到代理模式通过新增一个代理类实现负责处理事务的开启和提交。假设我们要处理的是下面的类图Staff是我们要处理的实体类StaffDao是接口定义两个方法employ、paySalaryStaffDaoImpl是实际的DAO实现StaffDaoProxy是代理类负责事务开启和提交。 Dao的操作用伪代码实现StaffDaoImpl和代理类核心代码如下 public class StaffDaoImpl implements StaffDao {public void employ(Staff p) {System.out.println(employ staff: p);}public void paySalary(Staff p) {System.out.println(pay salary : p);} } public class StaffDaoProxy implements StaffDao {private StaffDao staffDao;public StaffDaoProxy(StaffDao staffDao) {this.staffDao staffDao;}public void employ(Staff p) {System.out.println(start transaction...);staffDao.employ(p);System.out.println(commit transaction...);}public void paySalary(Staff p) {System.out.println(start transaction...);staffDao.paySalary(p);System.out.println(commit transaction...);} } 通过如下代码进行测试StaffDaoImpl只是完成了数据操作StaffDaoProxy会额外事务开启和提交操作 Staff staff new Staff(zhangsan,18); StaffDao staffDao new StaffDaoImpl(); // 直接调用 staffDao.employ(staff); staffDao.paySalary(staff);StaffDaoProxy proxy new StaffDaoProxy(staffDao); // 通过代理类使用 proxy.employ(staff); proxy.paySalary(staff); 2. 动态代理 代理模式确实达成了我们想要的效果如果每一个需要横切逻辑的类都需要通过代理模式类实现的话人力成本过高而且也不便于维护后续每一次修改都需要改大量的代理类。通过JDK提供的动态代理或者字节码操作的第三方库能解决这个问题。 2.1 JDK动态代理 我们来看一个通过JDK的Proxy类实现动态代理的示例首先要定义一个InvocationHandler的实现 public class TransactionInvocationHandler implements InvocationHandler {private StaffDao staffDao;public TransactionInvocationHandler(StaffDao staffDao) {this.staffDao staffDao;}public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println(start transaction...);Object result method.invoke(staffDao,args);System.out.println(commit transaction...);return result;} } 接着就可以通过Proxy.newInstance来创建代理类实例并测试其中staff和staffDao的实例和代理模式里的创建方式一样通过proxy.employ和proxy.paySalary调用输出也同之前的案例。 InvocationHandler invocationHandler new TransactionInvocationHandler(staffDao); StaffDao proxy (StaffDao) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),new Class[]{StaffDao.class},invocationHandler); proxy.employ(staff); proxy.paySalary(staff); 2.2 Cglib动态代理 JDK动态代理存在的一个问题是生成代理对象必须基于接口如果一个类没有实现接口就无法创建代理。好在还有大量的第三方库支持无接口的类生成动态代理。我们来看一个cglib的示例。和JDK代理类似首先我们要实现一个回调类不过cglib里回调类接口是MethodInterceptor。 import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy;import java.lang.reflect.Method;public class TransactionMethodInterceptor implements MethodInterceptor {private StaffDao staffDao;public TransactionMethodInterceptor(StaffDao staffDao) {this.staffDao staffDao;}public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {System.out.println(start transaction...);Object result method.invoke(staffDao, args);System.out.println(commit transaction...);return result;} } 紧接着使用Enhancer类创建代理类对象并使用测试也能得到同样的测试结果。 TransactionMethodInterceptor interceptor new TransactionMethodInterceptor(staffDao); Enhancer enhancer new Enhancer(); enhancer.setCallback(interceptor); enhancer.setSuperclass(StaffDao.class); StaffDao proxy (StaffDao) enhancer.create(); 3. Spring模式 动态代理解决代理模式带来的部分问题我不需要再为每个类手动创建子类所有横切逻辑都集中到InvocationHandler或MethodInterceptor中了。但是每次使用的时候都需要手工创建代理对象还是比较麻烦。Spring基于自己的能力对这个问题做了简化 3.1 ProxyFactory Spring提供了ProxyFactory来简化代理对象的创建频闭通过JDK或Cglib创建代理对象的差异(涉及类如下图)除此以外并没有其他改善。 同样需要实现一个回调类实现aopaliance提供的MethodInterceptor接口具体代码如下 import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation;public class SpringTransactionMethodInterceptor implements MethodInterceptor {Overridepublic Object invoke(MethodInvocation invocation) throws Throwable {System.out.println(start transaction...);Object result invocation.proceed();System.out.println(commit transaction...);return result;} } 然后使用ProxyFactory来创建代理对象并进行测试测试结果同之前的示例 ProxyFactory factory new ProxyFactory(); factory.setTarget(staffDao); factory.addAdvice(new SpringTransactionMethodInterceptor()); StaffDao proxy (StaffDao) factory.getProxy();Staff staff new Staff(zhangsan, 18); proxy.employ(staff); proxy.paySalary(staff); 3.2 ProxyFactoryBean 到目前为止我们依然需要手动创建代理类对象通过Spring本身的FactoryBean机制Spring AOP为我们提供了ProxyFactoryBean实现。首先通过xml配置Bean实现 bean idstaffDao classcom.lws.designPattern.StaffDaoImpl/ bean idspringTransaction classcom.lws.spring.SpringTransactionMethodInterceptor/ bean idstaffDaoProxy classorg.springframework.aop.framework.ProxyFactoryBeanproperty nametarget refstaffDao/property nameinterceptorNameslistvaluespringTransaction/value/list/property /bean 接着通过创建ApplicationContext获取Bean实例测试代码如下 ClassPathXmlApplicationContext context new ClassPathXmlApplicationContext(application.xml); StaffDao proxy context.getBean(staffDaoProxy, StaffDao.class); proxy.employ(staff); proxy.paySalary(staff); 3.3 AbstractAutoProxyCreator ProxyFactoryBean已经基本可以使用了只是每一个Bean要做代理时都需要手工配置一个ProxyFactoryBean使用起来还是略显繁琐。Spring提供了AbstractAutoProxyCreator来完成AOP代理的自动创建。这里我们以BeanNameAutoProxyCreator为例看看AutoProxyCreator是如何使用它是怎么工作的。同样先基于xml配置BeanNameAutoProxyFactory使用相同interceptorNames的所有Bean都可以通过这一个配置自动创建代理而且staffDao不需要和之前那样创建staffDao、staffDaoProxy两个Bean。 bean idstaffDao classcom.lws.designPattern.StaffDaoImpl/ bean idspringTransaction classcom.lws.spring.SpringTransactionMethodInterceptor/bean classorg.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreatorproperty namebeanNameslistvaluestaffDao/value/list/propertyproperty nameinterceptorNames valuespringTransaction/ /bean 接着只需要正常的获取staffDao的Bean实例并调用测试即可 Staff staff new Staff(zhangsan, 18); ClassPathXmlApplicationContext context new ClassPathXmlApplicationContext(application.xml); StaffDao proxy context.getBean(staffDao, StaffDao.class); proxy.employ(staff); proxy.paySalary(staff);应该承认BeanNameAutoProxyCreator的使用已经比较简单了对使用相同interceptorNames的AOP场景只需要把Bean实例名称添加到beanNames就行了。再进一步简化就是通过AnnotationAwareAspectJAutoProxyCreator来实现了它会自动判断Bean是否匹配AspectJ表达式对符号条件的Bean完成代理。后面的代码中我们会进行源码级解释现在我们先来讲讲Spring对AOP做的抽象以及它实现AOP的核心组件。 2. Spring AOP抽象 1. 核心术语 1.1 连接点(JoinPoint) 连接点是程序中客观存在的特定位置比如类初始化前、类初始化后、方法执行前、方法执行后等等。Spring AOP中只支持方法的连接点。连接到有两组信息组成一个是程序的执行点比如哪个类的哪个方法一个是相对位置比如方法执行前、方法返回后等等。Spring使用切点(Pointcut)表示执行点用增强(Advice)表示相对位置。 1.2 切点(Pointcut) 连接点是程序中客观存在的事务比如一个程序内有2个方法方法执行前、方法执行后、抛出异常时连接点个数就已经确定了如果只看这3类相对位置的话连接点就是6个。切点用来表示我们关心的连接点。Spring中使用Pointcut类表示切点。下图是Pointcut类的定义它有两个成员变量分别是ClassFilter实例、MethodMatcher实例。通过如下的UML图中的方法定义可以看到ClassFilter用来表示哪些类是满足当前切点要求MethodMatcher用来确定哪些方法满足当前切点要求。 Spring内部的核心实现类有下面这些后面我们会挑几个看一下如何使用。 1.3 增强(Advice) 在介绍连接点的时候我们提供到过连接点相对位置是通过增强(Advice)来表示的此外Advice还包含相对位置要执行的代码。下图是Spring提供的Advice的核心类。我们日常使用的较多的就是在图的中心位置的4个类: MethodBeforeAdvice方法执行前增强MethodInterceptor方法环绕增强AfterReturningAdvice方法返回后增强ThrowsAdvice方法抛异常是的正常这里需要特别注意ThrowsAdvice是一个标记接口Spring通过反射调用查看类JavaDoc有描述对方法签名的限制 1.4 切面(Aspect) 从之前的定义中可知Pointcut和Advice已经完整的定义了在哪里执行什么增强逻辑。切面有切点(Pointcut)和增强(引介)组成即包括横切逻辑的定义也包括连接点的定义。 1.5 目标对象(Target) 要进行增强逻辑的目标类在我们前面的例子里StaffDao类的实例就是目标对象。 1.6 代理对象(Proxy) 对目标对象进行增强后生成的对象就称为代理对象这个对象已经包含增强的执行逻辑。 2. 核心组件 这张图里给出了Spring AOP中的核心流程涉及的组件包括怎么定义切点(Pointcut)增强(Advice)并且通过组合Pointcut和Advice获得Advisor的定义。拿到Advisor后我们可以使用ProxyFactory将Advisor和目标对象(target)组合生成代对象。Spring默认支持两种生成代理对象的实现一种是基于JDK的实现JdkDynamicAopProxy一种是基于Cglib的实现ObjenesisCglibAopProxy。 每一个组件都有大量的实现类这里不进行展开。接下来我们对几个关键点做详细的说明 2.1 AutoProxyCreator工作原理 BeanNameAutoProxyCreator继承自AbstractAutoProxyCreator实现了Bean生命周期里的InstantiationAwareBeanFactoryProcessor、BeanPostProcessor覆写的是两个方法: postProcessBeforeInstantiation、postProcessAfterInitialization核心流程图如下: 对于定义了customTargetSource的AbstractAutoProxyCreatorBean不会走正常的实例化流程在postProcessBeforeInstantiation就通过TargetSource实例化并创建代理返回。日常开发中我们极少使用TargetSourceTargetSource适用于aop时期望目标对象(target)支持池化或者热替换的场景更多TargetSource信息可以阅读Spring官方文档中关于Using TargetSources章节。 BeanNameAutoProxy主要覆写了AbstractAutoProxyCreator以下几个方法: isSupportedBeanName基于配置的beanNames判断当前bean是否支持自动创建代理对象getAdvicesAndAdvisorsForBean支持的时候返回空数组不支持返回null BeanNameAutoProxyCreator的Advice和Advisor对象的注入主要时通过interceptorNames做为bean名称从容器中查找的具体实现看AbstractorAutoProxyCreator的buildAdvisors实现 AnnotationAwareAspectJAutoProxyCreator基于AbstractAutoProxyCreator实现不适用interceptorNames核心逻辑在于查找bean匹配的Advisor通过findCandidateAdvisors查找候选Advisor。 以下是AbstractAutoProxyCreator的骨干代码实现类基于下面的模板修改部分逻辑。 Overridepublic Object postProcessBeforeInstantiation(Class? beanClass, String beanName) {...TargetSource targetSource getCustomTargetSource(beanClass, beanName); // 自定义customTargetSourceCreator的Beanif (targetSource ! null) {if (StringUtils.hasLength(beanName)) {this.targetSourcedBeans.add(beanName);}Object[] specificInterceptors getAdvicesAndAdvisorsForBean(beanClass, beanName, targetSource); // 通过自定义TargetSource直接返回BeanObject proxy createProxy(beanClass, beanName, specificInterceptors, targetSource);this.proxyTypes.put(cacheKey, proxy.getClass());return proxy;}...}Overridepublic Object postProcessAfterInitialization(Nullable Object bean, String beanName) {if (bean ! null) {Object cacheKey getCacheKey(bean.getClass(), beanName);if (this.earlyBeanReferences.remove(cacheKey) ! bean) {return wrapIfNecessary(bean, beanName, cacheKey);}}return bean;} 2.2 EnableAspectJAutoProxy工作原理 EnableAspectJAutoProxy通过在自身注解Import引入ImportBeanDefinitionRegistrar实现ImportBeanDefinitionRegistrar接口允许用户通过代码注册自己的BeanDefinition。 Import({AspectJAutoProxyRegistrar.class}) public interface EnableAspectJAutoProxy AspectJAutoProxyRegistrar的核心代码如下: class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);AnnotationAttributes enableAspectJAutoProxy AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);...} } 进一步往AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary下面追踪我们发现自动注册了AnnotationAwareAspectJAutoProxyCreator结合上面我们对AutoProxyCreator的了解整个基于注解的配置AOP的流程就通顺了。 3. Spring AOP案例 基于上面对原理的探究我们能理解怎么从Advice、Pointcut开始创建Advisor怎么利用ProxyFactoryBean创建代理通过AutoProxyCreator让Spring自动创建代理Spring对所有这些元素的抽象以及相互之间如何协同。然而在显示工作中仅仅知道这些是不够的我们不可能每次都从最原始的MethodBeforceAdvice来创建我们的Advice不可能从ClassFilter、MethodMatcher开始定义Pointcut这样的话使用成本太高了Spring提供了大量的内置类型降低我们使用Spring AOP的成本。下一篇中我们会专注提供实战案例包括但不限于如下主题 1.使用Advice 2.使用Advisor 3.使用BeanNameAutoProxyCreator 4.使用AnnotationAwareAspectJAutoProxyCreator 5.使用aop名称空间 6.使用Aspect注解
http://www.w-s-a.com/news/210861/

相关文章:

  • 新乡网站开发wordpress 产品分类侧边栏
  • 网站自己做自己的品牌好做互联网企业分类
  • 项目网站建设方案石家庄网站快速排名
  • 网站开发大作业报告做电商网站的参考书
  • Apache局域网网站制作wordpress外链自动保存
  • 网站备案号要怎么查询千锋教育培训机构地址
  • 门户网站建设要求几款免费流程图制作软件
  • 花生壳域名可以做网站域名吗wordpress内链工具
  • 猎头公司网站模板网站伪静态作用
  • 工程建设教育网站html成品网页模板下载
  • 同一ip 网站 权重wordpress 菜单 小图标
  • 网站没有icp备案wordpress d8主题 4.1
  • 手机网站建设推荐企业宣传页模板
  • 杭州市富阳区建设局网站动态域名做网站
  • 网站如何免费做SEO优化靖安县城乡规划建设局网站
  • 室内设计网站平台学新媒体运营最好的培训学校
  • 招聘网站建设工作总结湘潭seo
  • 台山网站设计哈尔滨网站建设外包公司
  • 常州城投建设招标网站网页设计入门教学视频
  • 石家庄教育平台网站建设wordpress 访问量统计
  • 为什么买的网站模版不好用ftp网站建设
  • 做网站办公照片crm系统视频
  • 网站建设 招标文件南昌做网络推广的
  • 增城电子商务网站建设浙江省住房和城乡建设部网站
  • 企业网站宽度给多少手机软件开发公司排名
  • 装修设计网站哪个平台最好免费自助建站工具
  • 网站建设规划结构网站服务费怎么做分录
  • 哪里有做网站的公司微商怎么开店步骤
  • 访问不了服务器的网站北京工业产品设计公司
  • 怎么棋牌网站建设口碑好的福州网站建设