`
lovnet
  • 浏览: 6671595 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
文章分类
社区版块
存档分类
最新评论

Spring高级程序设计 6 Spring AOP 进阶

 
阅读更多
1AOP简介
通知(Advice):通知定义了切面是什么以及何时使用。除了要描述切面要完成的工作,通知还解决了何时执行这个工作的问题。
连接点(Joinpoint):连接点是在程序执行过程中能够插入切面的一个点。这个店可以是方法被调用时、异常被抛出时、甚至字段被编辑时。切面代码可以通过这些点插入到程序的一般流程之中,从而添加新的行为。
切入点(Poincut):切入点可以缩小切面通知的连接点的范围。如果说通知定义了切面的“什么”和“何时”,那么切入点就定义了“何地”。
切面(Aspect):切面是通知和切入点的组合。
引入(Introduction):“引入”允许我们向现有的类添加新方法或者属性。
目标(Target):被通知的对象。
代理(Proxy):是向目标对象应用通知之后被创建的对象。
织入(Weaving):是把切面应用到目标对象来创建新的代理对象的过程。编译时、类加载时、运行时。



主流的Spring:
AspectJ\JBoss AOP\Spring AOP


Spring对AOP的支持:
经典的基于代理的AOP(各版本Spring);
@AspectJ注解驱动的切面。(仅Spring2.0);
纯POJO切面(仅Spring2.0);
注入式AspectJ切面(各版本Spring)。



Spring通知是用Java编写的:
Spring创建的全部通知都是用标准的Java编写的。

Spring在运行时通知对象:
Spring利用代理类包裹切面,从而把他们注入到Spring管理的Bean里。

Spring只支持方法连接点:
由于Spring是基于动态代理的,他只支持方法连接点。





2创建典型的Spring切面

Spring AOP的通知类型:
Before(前):org.springframework.aop.MethodBeforeAdvice
After-returning(返回后):org.springframework.aop.AfterReturningAdvice
After-throwing(抛出后):org.springframework.aop.ThrowsAdvice
Around(包围):org.aopalliance.intercept.MethodInterceptor
Introduction(引入):org.springframework.aop.IntroductionInterceptor


除了Around之外,这些接口都属于Spring。




demo:
通知调用的方法类
  1. packagecn.partner4java.springidol;
  2. /**
  3. * 观众需要做的动作
  4. * (就是当调用演唱的时候,把这些动作顺序的加入到演唱的前后)
  5. * @author partner4java
  6. *
  7. */
  8. publicclassAudience {
  9. publicvoidtakeSeats(){
  10. System.out.println("The audience is taking their seats.");
  11. }
  12. publicvoidappluad(){
  13. System.out.println("CLAP CLAP!");
  14. }
  15. publicvoiddemandRefund(){
  16. System.out.println("Boo! We want our moeny back!");
  17. }
  18. }

定义两种实现方式的通知:
方式1:利用前置、后置、异常通知
  1. packagecn.partner4java.springidol;
  2. importjava.lang.reflect.Method;
  3. importorg.springframework.aop.AfterReturningAdvice;
  4. importorg.springframework.aop.MethodBeforeAdvice;
  5. importorg.springframework.aop.ThrowsAdvice;
  6. /**
  7. * Audience 的通知
  8. * 利用前置、后置、异常通知
  9. * @author partner4java
  10. *
  11. */
  12. publicclassAudienceAdviceimplementsMethodBeforeAdvice,
  13. AfterReturningAdvice, ThrowsAdvice {
  14. privateAudience audience;
  15. publicvoidsetAudience(Audience audience) {
  16. this.audience = audience;
  17. }
  18. publicvoidbefore(Method method, Object[] args, Object target)
  19. throwsThrowable {
  20. audience.takeSeats();
  21. }
  22. publicvoidafterReturning(Object returnValue, Method method,
  23. Object[] args, Object target)throwsThrowable {
  24. audience.appluad();
  25. }
  26. //There are not any methods on this interface, as methods are invoked by reflection.
  27. publicvoidafterThrowing(Throwable throwable){
  28. audience.demandRefund();
  29. }
  30. }

方式2:环绕通知
  1. packagecn.partner4java.springidol;
  2. importorg.aopalliance.intercept.MethodInterceptor;
  3. importorg.aopalliance.intercept.MethodInvocation;
  4. /**
  5. * Audience 的环绕通知
  6. * @author partner4java
  7. *
  8. */
  9. publicclassAudienceAroundAdviceimplementsMethodInterceptor {
  10. privateAudience audience;
  11. publicvoidsetAudience(Audience audience) {
  12. this.audience = audience;
  13. }
  14. publicObject invoke(MethodInvocation invocation)throwsThrowable {
  15. try{
  16. audience.takeSeats();
  17. Object returnValue = invocation.proceed();
  18. audience.appluad();
  19. returnreturnValue;
  20. }catch(Exception e) {
  21. audience.demandRefund();
  22. throwe;
  23. }
  24. }
  25. }

定义切点和通知者:
声明正则表达式切点、联合切点与通知者:
  1. <?xml version="1.0"encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:aop="http://www.springframework.org/schema/aop"
  5. xsi:schemaLocation="
  6. http://www.springframework.org/schema/beans
  7. http://www.springframework.org/schema/beans/spring-beans.xsd
  8. http://www.springframework.org/schema/aop
  9. http://www.springframework.org/schema/aop/spring-aop.xsd">
  10. <bean id="audience"class="cn.partner4java.springidol.Audience"/>
  11. <!-- 通知(Advice):通知定义了切面是什么以及何时使用 -->
  12. <bean id="advice1"class="cn.partner4java.springidol.AudienceAdvice">
  13. <property name="audience"ref="audience"></property>
  14. </bean>
  15. <bean id="advice2"class="cn.partner4java.springidol.AudienceAroundAdvice">
  16. <property name="audience"ref="audience"></property>
  17. </bean>
  18. <!-- 切入点(Poincut):切入点可以缩小切面通知的连接点的范围 -->
  19. <bean id="performancePointcut1"class="org.springframework.aop.support.JdkRegexpMethodPointcut">
  20. <property name="pattern"value=".*perform"></property>
  21. </bean>
  22. <!-- 定义AspectJ方式切点 -->
  23. <bean id="performancePointcut2"class="org.springframework.aop.aspectj.AspectJExpressionPointcut">
  24. <property name="expression"value="execution(* Performer+.perform(..))"></property>
  25. </bean>
  26. <!-- 切面(Aspect):切面是通知和切入点的组合(通知者)-->
  27. <bean id="audienceAdvisor1"class="org.springframework.aop.support.DefaultPointcutAdvisor">
  28. <property name="advice"ref="advice1"></property>
  29. <property name="pointcut"ref="performancePointcut1"></property>
  30. </bean>
  31. <bean id="audienceAdvisor2"class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
  32. <property name="advice"ref="advice1"></property>
  33. <property name="pattern"value=".*perform"></property>
  34. </bean>
  35. <bean id="performer"class="cn.partner4java.springidol.PerformerBean"></bean>
  36. </beans>


定义AspectJ切点
正则表达式虽然可以作为切点定义语言来使用,但他并不是针对切点而创建的,其主要用途换是文本解析。与之相比,从AspectJ里定义切点的方式就可以看出AspectJ的切点语言是一种真正的切点表达式语言。


使用ProxyFactoryBean:
代理(Proxy):是向目标对象应用通知之后被创建的对象
利用ProxyFactoryBean代理被切面的对象。
  1. <?xml version="1.0"encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:aop="http://www.springframework.org/schema/aop"
  5. xsi:schemaLocation="
  6. http://www.springframework.org/schema/beans
  7. http://www.springframework.org/schema/beans/spring-beans.xsd
  8. http://www.springframework.org/schema/aop
  9. http://www.springframework.org/schema/aop/spring-aop.xsd">
  10. <bean id="audience"class="cn.partner4java.springidol.Audience"/>
  11. <!-- 通知(Advice):通知定义了切面是什么以及何时使用 -->
  12. <bean id="advice1"class="cn.partner4java.springidol.AudienceAdvice">
  13. <property name="audience"ref="audience"></property>
  14. </bean>
  15. <bean id="advice2"class="cn.partner4java.springidol.AudienceAroundAdvice">
  16. <property name="audience"ref="audience"></property>
  17. </bean>
  18. <!-- 切入点(Poincut):切入点可以缩小切面通知的连接点的范围 -->
  19. <bean id="performancePointcut1"class="org.springframework.aop.support.JdkRegexpMethodPointcut">
  20. <property name="pattern"value=".*perform"></property>
  21. </bean>
  22. <!-- 定义AspectJ方式切点 -->
  23. <bean id="performancePointcut2"class="org.springframework.aop.aspectj.AspectJExpressionPointcut">
  24. <property name="expression"value="execution(* Performer+.perform(..))"></property>
  25. </bean>
  26. <!-- 切面(Aspect):切面是通知和切入点的组合(通知者)-->
  27. <bean id="audienceAdvisor1"class="org.springframework.aop.support.DefaultPointcutAdvisor">
  28. <property name="advice"ref="advice1"></property>
  29. <property name="pointcut"ref="performancePointcut1"></property>
  30. </bean>
  31. <bean id="audienceAdvisor2"class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
  32. <property name="advice"ref="advice1"></property>
  33. <property name="pattern"value=".*perform"></property>
  34. </bean>
  35. <!-- 使用ProxyFactoryBean -->
  36. <bean id="performer"class="cn.partner4java.springidol.PerformerBean"></bean>
  37. <bean id="duke"class="org.springframework.aop.framework.ProxyFactoryBean">
  38. <property name="target"ref="performer"></property>
  39. <property name="interceptorNames"value="audienceAdvisor1"></property>
  40. <property name="proxyInterfaces"value="cn.partner4java.springidol.Performer"></property>
  41. </bean>
  42. </beans>

调用:
  1. packagecn.partner4java.springidol;
  2. importorg.springframework.context.ApplicationContext;
  3. importorg.springframework.context.support.ClassPathXmlApplicationContext;
  4. publicclassHelloWorld {
  5. publicstaticvoidmain(String[] args) {
  6. ApplicationContext ctx =newClassPathXmlApplicationContext(
  7. "/META-INF/spring/springido.xml");
  8. Performer performer = (Performer) ctx.getBean("duke");
  9. performer.perform();
  10. }
  11. }






















3自动代理
@AspectJ注解
@AspectJ跟AspectJ没有关系。他是Spring用来解析连接点和通知的一组java 5注解。


demo1:
  1. packagecn.partner4java.spring.aspectj;
  2. importorg.aspectj.lang.ProceedingJoinPoint;
  3. importorg.aspectj.lang.annotation.Around;
  4. importorg.aspectj.lang.annotation.Aspect;
  5. /**
  6. * 通过@Aspect注解实现日志记录
  7. * @author partner4java
  8. *
  9. */
  10. @Aspect
  11. publicclassLoggingAspect {
  12. @Around("execution(* cn.partner4java.spring.aspectj.*.*(..))")
  13. publicObject log(ProceedingJoinPoint joinPoint)throwsThrowable {
  14. System.out.println("begin");
  15. Object ret = joinPoint.proceed();
  16. System.out.println("after");
  17. returnret;
  18. }
  19. }
  1. packagecn.partner4java.spring.aspectj;
  2. /**
  3. * 被测试的bean
  4. * @author partner4java
  5. *
  6. */
  7. publicclassTestBean {
  8. publicvoidwork() {
  9. System.out.println("work");
  10. }
  11. publicvoidstop() {
  12. System.out.println("stop");
  13. }
  14. }
  1. <?xml version="1.0"encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:aop="http://www.springframework.org/schema/aop"
  5. xsi:schemaLocation="
  6. http://www.springframework.org/schema/beans
  7. http://www.springframework.org/schema/beans/spring-beans.xsd
  8. http://www.springframework.org/schema/aop
  9. http://www.springframework.org/schema/aop/spring-aop.xsd">
  10. <bean id="test"class="cn.partner4java.spring.aspectj.TestBean"/>
  11. <beanclass="cn.partner4java.spring.aspectj.LoggingAspect">
  12. </bean>
  13. <aop:aspectj-autoproxy />
  14. </beans>
  1. packagecn.partner4java.spring.aspectj;
  2. importorg.springframework.context.ApplicationContext;
  3. importorg.springframework.context.support.ClassPathXmlApplicationContext;
  4. publicclassLoggingAspectDemo {
  5. publicstaticvoidmain(String[] args) {
  6. ApplicationContext ac =newClassPathXmlApplicationContext(
  7. "/META-INF/spring/ataspectjdemo1-context.xml"
  8. );
  9. TestBean testBean = (TestBean) ac.getBean("test");
  10. testBean.work();
  11. testBean.stop();
  12. //后台打印:
  13. //begin
  14. //work
  15. //after
  16. //begin
  17. //stop
  18. //after
  19. }
  20. }






@AspectJ方面详解
切入点声明表达式可以引入别人的表达式如:
@Pointcut("execution(* com.apress.prospring2.ch06.simple.TestBean.*(..))")
private void testBeanExecution() { }

@Around("testBeanExecution()")
public Object log(ProceedingJoinPoint pjp) throws Throwable {

或者

@Around("SystemPointcuts.testBeanExecution()")
public Object log(ProceedingJoinPoint pjp) throws Throwable {



切入点表达式:
execution:匹配方法执行连接点。我们可以指定包、类或者方法名,以及方法的可见性、返回值和参数类型。这是应用的最为广泛的切入点表达式。
within:匹配那些在已声明的类型中执行的连接点。
this:通过用bean引用的类型跟指定的类型做对比来匹配连接点。
args:通过比较方法的参数类型跟指定的参数类型来匹配连接点。
@target:通过检查调用目标对象是否具有特定注解来匹配连接点。
@args:跟args类似,不过@args检查的是方法参数的注解而不是他们的类型。
@within:跟within相似,这个表达式匹配那些带有特定注解的类中执行的连接点。
@annotation:通过检查讲被调用的方法上的注解是否为指定的注解来匹配连接点。
bean:通过比较bean的ID来匹配连接点,我们也可以在bean名模式中使用通配符。


我们可以使用||(或)和&&(与)组合切入点表达式。!(非)取否。




探讨切入点表达式:
1、execution表达式
如:
* com.partner4java..*.*(..)
第一个*表示任意返回类型,..*表示包下的所有类,*(..)表示任意方法和任意参数.


2、within表达式
within(com..TestBean):匹配从TestBean的方法中产生的调用
within(com..*):匹配在com包及其子包的任意类中对任意方法调用的执行过程的切入点。


3、this表达式
this表达式和within表达有些类似,但是不能使用..或者*等通配符。
this(class-name)


4、target表达式
和this完全一样。

5、args表达式
args(type-pattern?(,type-pattern)*)
可以使用..通配符
execution(* SimpleBean.*(String,String))
args(Integer,..,String)


6、@target表达式













4定义纯粹的POJO切面
Spring开发组意识到使用ProxyFactoryBean有些欠优雅,所以致力于提供一种更好的切面声明方式。Spring 2.0里新的XML配置元素就体现出了这种努力。


Spring 2.0的AOP配置元素:
<aop:advisor>:定义一个AOP通知者
<aop:after>:定义一个AOP后通知(不考虑被通知的方法是否成功返回)
<aop:after-returning>:定义一个AOP返回后通知
<aop:after-throwing>:定义一个AOP抛出后通知
<aop:around>:定义一个AOP包围通知
<aop:aspect>:定义一个切面
<aop:before>:顶一个AOP前置通知
<aop:config>:顶级AOP元素。大多数<aop:*>元素必须包含在
<aop:pointcut>:定义一个切点


demo:
使用上面的元素来定义一个完整的切面,其中包含通知者和切入点,不同的是,我们不需要自己声明代理(Proxy)就完成了织入(Weaving)。
  1. <?xml version="1.0"encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:aop="http://www.springframework.org/schema/aop"
  5. xsi:schemaLocation="
  6. http://www.springframework.org/schema/beans
  7. http://www.springframework.org/schema/beans/spring-beans.xsd
  8. http://www.springframework.org/schema/aop
  9. http://www.springframework.org/schema/aop/spring-aop.xsd">
  10. <bean id="audience"class="cn.partner4java.springidol.Audience"/>
  11. <bean id="performer"class="cn.partner4java.springidol.PerformerBean"></bean>
  12. <aop:config>
  13. <aop:aspect ref="audience">
  14. <aop:pointcut expression="execution(* *.perform*(..))"id="performance"/>
  15. <aop:before method="takeSeats"pointcut-ref="performance"/>
  16. <aop:after-returning method="appluad"pointcut-ref="performance"/>
  17. <aop:after-throwing method="demandRefund"pointcut-ref="performance"/>
  18. </aop:aspect>
  19. </aop:config>
  20. </beans>

调用:
  1. ApplicationContext ctx =newClassPathXmlApplicationContext(
  2. "/META-INF/spring/spring-pojo1.xml");
  3. Performer performer = (Performer) ctx.getBean("performer");
  4. performer.perform();



















5注入AspectJ切面

虽然Spring AOP对于大多数切面程序来说就足够了,但是与AspectJ相比,他只能算是一个功能较弱的AOP解决方案。AspectJ提供了Spring AOP不可能实现的多种切点类型。

(如果想更深入的了解AspectJ,可以阅读Raminvas Ladded的AspectJ in Action(Manning,2003))


demo:
创建第一个AspectJ方面。

Spring通过添加aspectOf()方法增加对AspectJ的支持,不需要你额外的管理容器。
创建一个aj格式的文件,也就是AspectJ的切面:
  1. packagecn.partner4java.aspectj;
  2. publicaspect StockServiceAspect {
  3. privateString suffix;
  4. privateString prefix;
  5. publicvoidsetPrefix(String prefix) {
  6. this.prefix = prefix;
  7. }
  8. publicvoidsetSuffix(String suffix) {
  9. this.suffix = suffix;
  10. }
  11. pointcut doServiceCall() :
  12. execution(* cn.partner4java.aspectj.*.*(..));
  13. before() : doServiceCall() {
  14. System.out.println(this.prefix);
  15. }
  16. after() : doServiceCall() {
  17. System.out.println(this.suffix);
  18. }
  19. }

配置文件:额外添加factory-method="aspectOf"知名是AspectJ文件
  1. <?xml version="1.0"encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation="
  5. http://www.springframework.org/schema/beans
  6. http://www.springframework.org/schema/beans/spring-beans.xsd">
  7. <bean id="stockService"class="cn.partner4java.aspectj.DefaultStockService"/>
  8. <!-- 额外添加factory-method="aspectOf"知名是AspectJ文件 -->
  9. <beanclass="cn.partner4java.aspectj.StockServiceAspect"
  10. factory-method="aspectOf">
  11. <property name="prefix"value="Before call"/>
  12. <property name="suffix"value="After call"/>
  13. </bean>
  14. </beans>

调用:为了让示例程序正常运行,我们必须使用AspectJ编译器(需要像使用JDK那样安装,配置环境变量等)
  1. packagecn.partner4java.aspectj;
  2. importorg.springframework.context.ApplicationContext;
  3. importorg.springframework.context.support.ClassPathXmlApplicationContext;
  4. publicclassHelloWorld {
  5. publicstaticvoidmain(String[] args) {
  6. //为了让示例程序正常运行,我们必须使用AspectJ编译器
  7. ApplicationContext ac =newClassPathXmlApplicationContext(
  8. "/META-INF/spring/aspectjdemo1-context.xml"
  9. );
  10. StockService stockService = (StockService) ac.getBean("stockService");
  11. System.out.println(stockService.getStockLevel("ABC"));
  12. }
  13. }


AspectJ还可以指定“加载时织入”:
使用spring-agent.jar作为JVM代理来替代<aop:aspectj-autoproxy/>,并使用上下文命名空间来初始化加载时织入。
除了ApplicationContext的XML配置文件之外,还需要创建META-INF/aop.xml文件。这个aop.xml文件是一个标准的AspectJ组件。他告诉AspectJ注入器在加载时织入哪些类。
Spring加入<context:load-time-weaver>,可以配置aspectj-weaving,设置on或者off设置开启或关闭织入。

分享到:
评论

相关推荐

    Spring框架进阶:成为Java技术大牛的秘密.zip

    文章涵盖了Spring框架的模块化设计、控制反转(IoC)、依赖注入(DI)、面向切面编程(AOP)、Spring MVC和Web开发、Spring Data和数据访问等内容。此外,文中还提供了实践项目开发的建议,帮助读者将所学知识运用到...

    Spring.3.x企业应用开发实战(完整版).part2

    第6章 Spring AOP基础 6.1 AOP概述 6.1.1 AOP到底是什么 6.1.2 AOP术语 6.1.3 AOP的实现者 6.2 基础知识 6.2.1 带有横切逻辑的实例 6.2.2 JDK动态代理 6.2.3 CGLib动态代理 6.2.4 AOP联盟 6.2.5 代理知识小结 6.3 ...

    Spring3.x企业应用开发实战(完整版) part1

    第6章 Spring AOP基础 6.1 AOP概述 6.1.1 AOP到底是什么 6.1.2 AOP术语 6.1.3 AOP的实现者 6.2 基础知识 6.2.1 带有横切逻辑的实例 6.2.2 JDK动态代理 6.2.3 CGLib动态代理 6.2.4 AOP联盟 6.2.5 代理知识小结 6.3 ...

    基于springboot演示resuful api、mock请求、validate验证、异常捕捉、aop切面编程+源代码+文档说

    2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。...

    java web技术开发大全(最全最新)

    本次出版的“原创经典,程序员典藏”系列图书是清华大学出版社的重点精品计算机图书,旨在帮助读者全面学习各类程序设计语言和开发工具,提高开发水平。同时也为广大程序员提供良好的技术参考,以便作为案头必备的...

    java web开发技术大全

    本次出版的“原创经典,程序员典藏”系列图书是清华大学出版社的重点精品计算机图书,旨在帮助读者全面学习各类程序设计语言和开发工具,提高开发水平。同时也为广大程序员提供良好的技术参考,以便作为案头必备的...

    Java语言基础下载

    第三章:面向对象的程序设计 31 学习目标 31 类和对象的描述 32 声明类 32 声明属性 33 声明成员方法 34 源文件的布局 36 包的声明 36 包与目录的布局 38 内容总结 45 独立实践 46 第四章: Java语法基础 47 学习...

    asp.net知识库

    将 ASP.NET 2.0 应用程序服务配置为使用 SQL Server 2000 或 SQL Server 2005 ASP.NET 2.0 中的数据源控件 使用 ASP.NET 2.0 ObjectDataSource 控件 ASP.NET 2.0 的内部变化 使用SQL Cache Dependency 代替 ...

    J2EE应用开发详解

    254 15.3 依赖注入 259 15.3.1 Constructor注入 259 15.3.2 Setter注入 261 15.3.3 Method注入 263 15.4 Spring AOP技术 266 15.4.1 装备(advices) 267 15.4.2 Spring AOP的传统用法 275 15.4.3 基于@AspectJ注释...

    基于HTML5_BootStrap_SSM图书查询借阅网站+源代码+文档说明+数据库.zip

    5 spring容器内部使用拦截器,以Spring AOP的方式实现事务控制管理。 -------- 不懂运行,下载完可以私聊问,可远程教学 该资源内项目源码是个人的毕设,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分...

    JSP基于SSM实现的和EasyUI公司员工管理系统毕业源代码+文档说明

    2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。...

    领域驱动设计与模式实战

    第5章 领域驱动设计进阶 5.1 通过简单的TDD实验来精化领域模型 5.1.1 从Order和OrderFactory的创建开始 5.1.2 一些领域逻辑 5.1.3 第二个任务:OrderRepository+OrderNumber 5.1.4 重建持久化的实体:如何从外部设置...

    基于Springboot + Vue 开发的前后端分离博客(PC端自适应+移动端微信小程序+移动端App)+源代码+文档说明

    2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。...

Global site tag (gtag.js) - Google Analytics