第七章节 spring AOP

news/2024/5/24 11:18:36/

《Spring》篇章整体栏目
—————————————————————————————
【第一章】spring 概念与体系结构
【第二章】spring IoC 的工作原理
【第三章】spring IOC与Bean环境搭建与应用
【第四章】spring bean定义
【第五章】Spring 集合注入、作用域
【第六章】Spring 自动装配
【第七章】spring AOP
【第八章】Spring 集成JdbcTemplate
【第九章】Spring数据库事务管理
【第十章】Spring 集成Redis
【第十一章】Spring实战之打造新闻系统后端接口
—————————————————————————————

目录

  • 前言
  • 1、AOP概念
    • 1.1、目前流行的AOP框架
    • 1.2、AOP术语
    • 1.3、Advice(增强处理)
    • 1.4、AOP类型
    • 1.4.1、动态 AOP
    • 1.4.2、静态 AOP
    • 1.5、在 Spring 框架中使用 AOP的优势
  • 2、Spring AOP
    • 2.1、连接点
    • 2.2、通知类型
    • 2.3、切面类型
      • 2.3.1、 一般切面开发例子
      • 2.3.2、 PointcutAdvisor 的 AOP 开发(带切点的切面)
      • 2.3.2.1、自动代理例子
      • 2.3.3、 根据切面中的信息创建代理对象
  • 3、集成AspectJ
    • 3.1、需要导入包
    • 3.2、基于XML的AspectJ AOP开发
      • 3.2.1、xml定义命名空间
      • 3.2.2、定义切面
      • 3.2.3、定义切入点
      • 3.2.4、定义通知
    • 3.3、基于注解的AspectJ AOP开发
      • 3.3.1、启用@AspectJ注解
        • 3.3.1.1、Java配置类
        • 3.3.1.2、XML配置
      • 3.3.2、定义切面
      • 3.3.3、运行
  • 4、aop实战练习
    • 1、src下面增加log.properties
    • 2、定义一个类,读取第一步的配置文件
    • 3、定义一个日志生成类 XXXX

—————————————————————————————

前言

Aspect Oriented Programming ,面向切面编程

1、AOP概念

Aspect Oriented Programming ,面向切面编程

1.1、目前流行的AOP框架

AOP 框架说明
SpringAOP是一款基于 AOP 编程的框架,它能够有效的减少系统间的重复代码,达到松耦合的目的。Spring AOP 使用纯 Java 实现,不需要专门的编译过程和类加载器,在运行期间通过代理方式向目标类植入增强的代码。Spring AOP 支持 2 种代理方式,分别是基于接口的 JDK 动态代理和基于继承的 CGLIB 动态代理。
AspectJ是一个基于 Java 语言的 AOP 框架,从 Spring 2.0 开始,Spring AOP 引入了对 AspectJ 的支持。AspectJ 扩展了 Java 语言,提供了一个专门的编译器,在编译时提供横向代码的植入。

1.2、AOP术语

名称说明
Joinpoint(连接点)AOP 的核心概念,指的是程序执行期间明确定义的一个点,例如方法的调用、类初始化、对象实例化等。在 Spring 中,连接点则指可以被动态代理拦截目标类的方法。
Pointcut(切入点)又称切点,指要对哪些 Joinpoint 进行拦截,即被拦截的连接点。
Advice(通知)指拦截到 Joinpoint 之后要执行的代码,即对切入点增强的内容。
Target(目标)指代理的目标对象,通常也被称为被通知(advised)对象。
Weaving(织入)指把增强代码应用到目标对象上,生成代理对象的过程。
Proxy(代理)指生成的代理对象。
Aspect(切面)切面是切入点(Pointcut)和通知(Advice)的结合。

1.3、Advice(增强处理)

通知说明
before(前置通知)通知方法在目标方法调用之前执行
after(后置通知)通知方法在目标方法返回或异常后调用
after-returning(返回后通知)通知方法会在目标方法返回后调用
after-throwing(抛出异常通知)通知方法会在目标方法抛出异常后调用
around(环绕通知)通知方法会将目标方法封装起来

1.4、AOP类型

1.4.1、动态 AOP

动态 AOP 的织入过程是在运行时动态执行的。其中最具代表性的动态 AOP 实现就是 Spring AOP,它会为所有被通知的对象创建代理对象,并通过代理对象对被原对象进行增强。
相较于静态 AOP 而言,动态 AOP 的性能通常较差,但随着技术的不断发展,它的性能也在不断的稳步提升。
动态 AOP 的优点是它可以轻松地对应用程序的所有切面进行修改,而无须对主程序代码进行重新编译。

1.4.2、静态 AOP

静态 AOP 是通过修改应用程序的实际 Java 字节码,根据需要修改和扩展程序代码来实现织入过程的。最具代表性的静态 AOP 实现是 AspectJ。
相较于动态 AOP 来说,性能较好。但它也有一个明显的缺点,那就是对切面的任何修改都需要重新编译整个应用程序。

1.5、在 Spring 框架中使用 AOP的优势

1、提供声明式企业服务;
2、允许用户实现自定义切面。在某些不适合用 OOP 编程的场景中,采用 AOP 来补充。
3、可以对业务逻辑的各个部分进行隔离,从而使业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时也提高了开发效率。

2、Spring AOP

代理技术描述
JDK 动态代理Spring AOP 默认的动态代理方式,若目标对象实现了若干接口,Spring 使用 JDK 的 java.lang.reflect.Proxy 类进行代理。
CGLIB 动态代理若目标对象没有实现任何接口,Spring 则使用 CGLIB 库生成目标对象的子类,以实现对目标对象的代理。

2.1、连接点

Spring AOP 只支持一种连接点类型:方法调用

2.2、通知类型

通知类型接口描述
前置通知org.springframework.aop.MethodBeforeAdvice在目标方法执行前实施增强。
后置通知org.springframework.aop.AfterAdvice在目标方法执行后实施增强。
后置返回通知org.springframework.aop.AfterReturningAdvice在目标方法执行完成,并返回一个返回值后实施增强。
环绕通知org.aopalliance.intercept.MethodInterceptor在目标方法执行前后实施增强。
异常通知org.springframework.aop.ThrowsAdvice在方法抛出异常后实施增强。
引入通知org.springframework.aop.IntroductionInterceptor在目标类中添加一些新的方法和属性。

2.3、切面类型

在 Spring AOP 中,切面可以分为三类:一般切面、切点切面和引介切面。

切面类型接口描述
一般切面org.springframework.aop.AdvisorSpring AOP 默认的切面类型。

由于 Advisor 接口仅包含一个 Advice(通知)类型的属性,而没有定义 PointCut(切入点),因此它表示一个不带切点的简单切面。

这样的切面会对目标对象(Target)中的所有方法进行拦截并织入增强代码。由于这个切面太过宽泛,因此我们一般不会直接使用。
切点切面org.springframework.aop.PointcutAdvisorAdvisor 的子接口,用来表示带切点的切面,该接口在 Advisor 的基础上还维护了一个 PointCut(切点)类型的属性。使用它,我们可以通过包名、类名、方法名等信息更加灵活的定义切面中的切入点,提供更具有适用性的切面。
引介切面org.springframework.aop.IntroductionAdvisorAdvisor 的子接口,用来代表引介切面,引介切面是对应引介增强的特殊的切面,它应用于类层面上,所以引介切面适用 ClassFilter 进行定义。

2.3.1、 一般切面开发例子

package com.xxxx.spring.dao;public interface NewsDAO {public void insert();public void delete();public void update();public void select();
}
package com.xxxx.spring.dao.impl;import com.xxxx.spring.dao.NewsDAO;public class UserDAOImpl implements NewsDAO {@Overridepublic void insert() {System.out.println("执行UserDAOImpl的insert()方法");}@Overridepublic void delete() {System.out.println("执行UserDAOImpl的delete()方法");}@Overridepublic void update() {System.out.println("执行UserDAOImpl的update()方法");}@Overridepublic void select() {System.out.println("执行UserDAOImpl的select()方法");}
}
package com.xxxx.spring.advice;import org.springframework.aop.MethodBeforeAdvice;import java.lang.reflect.Method;public class NewsDAOAdvice implements MethodBeforeAdvice {@Overridepublic void before(Method method, Object[] args, Object target) throws Throwable {System.out.println("执行前置操作.....");}
}
<?xml version="1.0" encoding="utf-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsd"><!--代理目标--><bean id="newsDAO" class="com.xxxx.spring.dao.impl.UserDAOImpl"/><!--定义前置增强--><bean id="newsDAOAdvice" class="com.xxxx.spring.advice.NewsDAOAdvice"/><!--生成代理对象--><bean id="newsDAOProxy" class="org.springframework.aop.framework.ProxyFactoryBean"><!--设置代理目标--><property name="target" ref="newsDAO"/><!--实现接口--><property name="proxyInterfaces" value="com.xxxx.spring.dao.NewsDAO"/><!--增强bean名称--><property name="interceptorNames" value="newsDAOAdvice"/></bean>
</beans>

Java测试代码:

ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("newsdao.xml");
NewsDAO newsDAOProxy = classPathXmlApplicationContext.getBean("newsDAOProxy", NewsDAO.class);
newsDAOProxy.delete();
newsDAOProxy.insert();

2.3.2、 PointcutAdvisor 的 AOP 开发(带切点的切面)

Spring 提供了多个 PointCutAdvisor 的实现,其中常用实现类如如下。

  • NameMatchMethodPointcutAdvisor:指定 Advice 所要应用到的目标方法名称,例如 hello* 代表所有以 hello 开头的所有方法。
  • RegExpMethodPointcutAdvisor:使用正则表达式来定义切点(PointCut),RegExpMethodPointcutAdvisor 包含一个 pattern 属性,该属性使用正则表达式描述需要拦截的方法。
package com.xxxx.spring.dao.impl;import com.xxxx.spring.dao.NewsDAO;public class NewsDAOImpl implements NewsDAO {@Overridepublic void insert() {System.out.println("执行UserDAOImpl的insert()方法");}@Overridepublic void inserts() {System.out.println("执行UserDAOImpl的inserts()方法");}@Overridepublic void delete() {System.out.println("执行UserDAOImpl的delete()方法");}@Overridepublic void update() {System.out.println("执行UserDAOImpl的update()方法");}@Overridepublic void select() {System.out.println("执行UserDAOImpl的select()方法");}
}
package com.xxxx.spring.advice;import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;public class NewsDAOAroundAdvice implements MethodInterceptor {@Overridepublic Object invoke(MethodInvocation invocation) throws Throwable {System.out.println("before");Object proceed = invocation.proceed();System.out.println("after");return proceed;}
}
<?xml version="1.0" encoding="utf-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsd"><!--代理目标--><bean id="newsDAO" class="com.xxxx.spring.dao.impl.NewsDAOImpl"/><!--定义前置增强--><bean id="newsDAOAdvice" class="com.xxxx.spring.advice.NewsDAOAroundAdvice"/><!--定义切面--><bean id="pointCutAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"><!--<property name="patterns" value=".*"/>--><property name="patterns" value="com.xxxx.spring.dao.impl.NewsDAOImpl.insert.*"/><property name="advice" ref="newsDAOAdvice"/></bean><!--生成代理对象--><bean id="newsDAOProxy" class="org.springframework.aop.framework.ProxyFactoryBean"><!--设置代理目标--><property name="target" ref="newsDAO"/><!--false JDK  true CGLIB--><property name="proxyTargetClass" value="true"/><!--增强bean名称--><property name="interceptorNames" value="pointCutAdvisor"/></bean></beans>

2.3.2.1、自动代理例子

如果每个 Bean 都通过 ProxyFactoryBean 创建,那么开发和维护成本会十分巨大
Spring 为我们提供了 3 种自动代理方案:

  • BeanNameAutoProxyCreator:根据 Bean 名称创建代理对象。
  • DefaultAdvisorAutoProxyCreator:根据 Advisor 本身包含信息创建代理对象。
  • AnnotationAwareAspectJAutoProxyCreator:基于 Bean 中的 AspectJ 注解进行自动代理对象
package com.xxxx.spring.dao.impl;import com.xxxx.spring.dao.NewsDAO;public class XXXDAOImpl{public void insert() {System.out.println("执行XXXDAOImpl的insert()方法");}public void inserts() {System.out.println("执行XXXDAOImpl的inserts()方法");}public void delete() {System.out.println("执行XXXDAOImpl的delete()方法");}public void update() {System.out.println("执行XXXDAOImpl的update()方法");}public void select() {System.out.println("执行XXXDAOImpl的select()方法");}
}
<?xml version="1.0" encoding="utf-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsd"><!--代理目标--><bean id="newsDAO" class="com.xxxx.spring.dao.impl.NewsDAOImpl"/><bean id="xxxDAO" class="com.xxxx.spring.dao.impl.XXXDAOImpl"/><!--定义前置增强--><bean id="newsDAOAdvice" class="com.xxxx.spring.advice.NewsDAOAdvice"/><!--定义环绕增强--><bean id="newsDAOAroundAdvice" class="com.xxxx.spring.advice.NewsDAOAroundAdvice"/><!--生成代理对象--><bean id="newsDAOProxy" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"><!--设置代理目标--><property name="beanNames" value="*DAO"/><!--增强bean名称--><property name="interceptorNames" value="newsDAOAdvice,newsDAOAroundAdvice"/></bean>
</beans>

2.3.3、 根据切面中的信息创建代理对象

<?xml version="1.0" encoding="utf-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsd"><!--代理目标--><bean id="newsDAO" class="com.xxxx.spring.dao.impl.NewsDAOImpl"/><bean id="xxxDAO" class="com.xxxx.spring.dao.impl.XXXDAOImpl"/><!--定义前置增强--><bean id="newsDAOAdvice" class="com.xxxx.spring.advice.NewsDAOAdvice"/><!--定义环绕增强--><bean id="newsDAOAroundAdvice" class="com.xxxx.spring.advice.NewsDAOAroundAdvice"/><!--定义切面--><bean id="pointCutAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"><!--<property name="patterns" value=".*"/>--><property name="patterns" value="com.xxxx.spring.dao.impl.XXXDAOImpl.insert.*"/><property name="advice" ref="newsDAOAroundAdvice"/></bean><!--根据切面信息创建自动代理--><bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
</beans>

3、集成AspectJ

Spring AOP 是一个简化版的 AOP 实现,并没有提供完整版的 AOP 功能。通常情况下,Spring AOP 是能够满足我们日常开发过程中的大多数场景的,但在某些情况下,我们可能需要使用 Spring AOP 范围外的某些 AOP 功能。比如Spring AOP 仅支持执行公共(public)非静态方法的调用作为连接点,如果我们需要向受保护的(protected)或私有的(private)的方法进行增强,此时就需要使用功能更加全面的 AOP 框架来实现,其中使用最多的就是 AspectJ。

3.1、需要导入包

spring-aspects-xxx.jar
aspectjweaver-xxxx.jar

<!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
<dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>5.3.0</version>
</dependency><!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.6</version>
</dependency>

3.2、基于XML的AspectJ AOP开发

Spring 提供了基于 XML 的 AOP 支持,并提供了一个名为“aop”的命名空间,该命名空间提供了一个 aop:config 元素。

  • 在 Spring 配置中,所有的切面信息(切面、切点、通知)都必须定义在 aop:config 元素中;
  • 在 Spring 配置中,可以使用多个 aop:config。
  • 每一个 aop:config 元素内可以包含 3 个子元素: pointcut、advisor 和 aspect ,这些子元素必须按照这个顺序进行声明。

3.2.1、xml定义命名空间

增加spring-aop

<?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-3.0.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-3.0.xsd "></beans>

3.2.2、定义切面

<aop:config><aop:aspect id="myAspect" ref="myBean"/>
</aop:config>

3.2.3、定义切入点

execution 的语法格式格式为:
execution([权限修饰符] [返回值类型] [类的完全限定名] [方法名称]([参数列表]) 其中:

  • 返回值类型、方法名、参数列表是必须配置的选项,而其它参数则为可选配置项。
  • 返回值类型:
    *表示可以为任何返回值。如果返回值为对象,则需指定全路径的类名。
    • 类的完全限定名:指定包名 + 类名。
    • 方法名:
      *代表所有方法,
      set* 代表以 set 开头的所有方法。
      • 参数列表:
        (…)代表所有参数;
        (*)代表只有一个参数,参数类型为任意类型;
        (*,String)代表有两个参数,第一个参数可以为任何值,第二个为 String 类型的值。

3.2.4、定义通知

   <!-- 前置通知 --><aop:before pointcut-ref="myPointCut" method="..."/>   <!-- 后置通知 --><aop:after-returning pointcut-ref="myPointCut" method="..."/><!-- 环绕通知 --><aop:around pointcut-ref="myPointCut" method="..."/><!-- 异常通知 --><aop:after-throwing pointcut-ref="myPointCut" method="..."/><!-- 最终通知 --><aop:after pointcut-ref="myPointCut" method="..."/>

列子:

/*** 新闻信息服务接口*/
public interface NewsDAO {void insert();void delete();void update();void select();
}
public class NewsDAOImpl implements NewsDAO {@Overridepublic void insert() {System.out.println("执行UserDAOImpl的insert()方法");}@Overridepublic void delete() {System.out.println("执行UserDAOImpl的delete()方法");//throw new RuntimeException("ddd");}@Overridepublic void update() {System.out.println("执行UserDAOImpl的update()方法");}@Overridepublic void select() {System.out.println("执行UserDAOImpl的select()方法");}
}

定义Apect类

public class NewsAspect {public void before() {System.out.println("前置增强……");}public void after() {System.out.println("最终增强……");}public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {System.out.println("环绕增强---前……");proceedingJoinPoint.proceed();System.out.println("环绕增强---后……");}public void afterThrow(Throwable exception) {System.out.println("异常增强…… 异常信息为:" + exception.getMessage());}public void afterReturning(Object returnValue) {System.out.println("后置返回增强…… 方法返回值为:" + returnValue);}
}

定义xml文件

<?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/beanshttp://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-3.0.xsd"><!--定义bean--><bean id="newsDAO" class="com.xxxx.spring.dao.impl.NewsDAOImpl"/><!--定义切面--><bean id="newsAspect" class="com.xxxx.spring.advice.NewsAspect"/><aop:config><!--定义切点--><aop:pointcut id="beforePointCut" expression="execution(* com.xxxx.spring.dao.NewsDAO.insert(..))"/><aop:pointcut id="throwPointCut" expression="execution(* com.xxxx.spring.dao.NewsDAO.update(..))"/><aop:pointcut id="afterRerturningPointCut" expression="execution(* com.xxxx.spring.dao.NewsDAO.delete(..))"/><aop:pointcut id="afterPointCut" expression="execution(* com.xxxx.spring.dao.NewsDAO.select(..))"/><aop:pointcut id="aroundPointCut" expression="execution(* com.xxxx.spring.dao.NewsDAO.update(..))"/><aop:aspect  ref="newsAspect"><aop:before method="before" pointcut-ref="beforePointCut"/><aop:after-throwing method="afterThrow" pointcut-ref="throwPointCut" throwing="exception"/><aop:after-returning method="afterReturning" pointcut-ref="afterRerturningPointCut" returning="returnValue"/><aop:after method="after" pointcut-ref="afterPointCut"/><aop:around method="around" pointcut-ref="aroundPointCut"/></aop:aspect></aop:config>
</beans>

3.3、基于注解的AspectJ AOP开发

AspectJ 框架为 AOP 开发提供了一套 @AspectJ 注解。它允许我们直接在 Java 类中通过注解的方式对切面(Aspect)、切入点(Pointcut)和增强(Advice)进行定义。

名称说明
@Aspect用于定义一个切面。
@Pointcut用于定义一个切入点。
@Before用于定义前置通知,相当于 BeforeAdvice。
@AfterReturning用于定义后置通知,相当于 AfterReturningAdvice。
@Around用于定义环绕通知,相当于 MethodInterceptor。
@AfterThrowing用于定义抛出通知,相当于 ThrowAdvice。
@After用于定义最终通知,不管是否异常,该通知都会执行。
@DeclareParents用于定义引介通知,相当于 IntroductionInterceptor

3.3.1、启用@AspectJ注解

Java配置类或者XML配置启用

3.3.1.1、Java配置类

@Configuration
@ComponentScan(basePackages = "com.xxxx.spring")
@EnableAspectJAutoProxy
public class AppConfig {
}

3.3.1.2、XML配置

<!-- 开启注解扫描 -->
<context:component-scan base-package="com.xxxx.spring">
</context:component-scan>
<!--开启AspectJ 自动代理-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

3.3.2、定义切面

@Component
@Aspect
public class NewsAspect {@Pointcut(value = "execution(* com.xxxx.spring.dao.NewsDAO.insert(..))")public void beforePointCut(){}@Before(value = "NewsAspect.beforePointCut()")public void before() {System.out.println("前置增强……");}@After(value = "execution(* com.xxxx.spring.dao.NewsDAO.select(..))")public void after() {System.out.println("最终增强……");}@Around(value="execution(* com.xxxx.spring.dao.NewsDAO.update(..))")public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {System.out.println(proceedingJoinPoint.getSignature().getName());System.out.println("环绕增强---前……");proceedingJoinPoint.proceed();System.out.println("环绕增强---后……");}@AfterThrowing(value = "execution(* com.xxxx.spring.dao.NewsDAO.update(..))",throwing = "exception")public void afterThrow(Throwable exception) {System.out.println("异常增强…… 异常信息为:" + exception.getMessage());}@AfterReturning(value = "execution(* com.xxxx.spring.dao.NewsDAO.update(..))",returning = "returnValue")public void afterReturning(Object returnValue) {System.out.println("后置返回增强…… 方法返回值为:" + returnValue);}
}

3.3.3、运行

public class Test05 {public static void main(String[] args) {AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(AppConfig.class);NewsDAO newsDAO = annotationConfigApplicationContext.getBean("newsDAO", NewsDAO.class);newsDAO.update();}
}

4、aop实战练习

定义日志框架

1、src下面增加log.properties

 log.file  //日志存放的位置log.format //日志格式log.level=DEBUG //日志等级    DEBUG/INFO/WARN/ERROR   log.target=console,file #日志输出

2、定义一个类,读取第一步的配置文件

3、定义一个日志生成类 XXXX

 根据第二步读到配置内容,执行日志的生成逻辑提供四个方法:debug、info、warn、error

http://www.ppmy.cn/news/48345.html

相关文章

什么是计算量flops,什么是参数量params?

flops与params 计算量对应我们之前的时间复杂度&#xff0c;参数量对应于我们之前的空间复杂度&#xff0c;这么说就很明显了 也就是计算量要看网络执行时间的长短&#xff0c;参数量要看占用显存的量 其中最重要的衡量CNN 模型所需的计算力就是flops&#xff1a; FLOPS&…

显存不够用?一种大模型加载时节约一半显存的方法

Loading huge PyTorch models with linear memory consumption 本文主要介绍了一种用于加载巨大模型权重时节约接近一半显存的方法 首先&#xff0c;创建一个模型: import torch from torch import nnclass BoringModel(nn.Sequential):def __init__(self):super().__init__…

【Leetcode -剑指Offer 22.链表中倒数第k个结点 -203.移除链表元素】

Leetcode Leetcode -剑指Offer 22.链表中倒数第k个结点Leetcode -203.移除链表元素 Leetcode -剑指Offer 22.链表中倒数第k个结点 题目&#xff1a;输入一个链表&#xff0c;输出该链表中倒数第k个节点。为了符合大多数人的习惯&#xff0c;本题从1开始计数&#xff0c;即链表…

OSCP-Clyde(rabbitmq中间件、erlang服务4369、修改Payload、nmap提权)

目录 扫描 FTP erlang服务(4369) 提权 扫描 21/tcp open ftp vsftpd 3.0.3 | ftp-anon: Anonymous FTP login allowed (FTP code 230) | drwxr-xr-x 2 ftp ftp 4096 Apr 24 2020 PackageKit | drwxr-xr-x 5 ftp ftp 4096 Apr 24 2020 apache2 | drwxr-xr-x 5 ftp ftp 409…

云原生之在kubernetes集群下部署Mysql应用

云原生之在kubernetes集群下部署mysql应用 一、Mysql介绍二、kubernetes集群介绍1.k8s简介2.k8s架构图 三、本次实践介绍1.本次实践简介2.本次环境规划 三、检查本地k8s集群环境1.检查k8s各节点状态2.检查k8s版本3.检查k8s系统pod状态 四、编辑mysql.yaml文件五、创建mysql应用…

Redis分布式锁有哪些缺点?如何解决?

目录 一、死锁问题&#xff1a; 二、锁竞争问题&#xff1a; 三、时效性问题&#xff1a; 四、单点故障问题&#xff1a; 五、高并发量下锁抢占时间长的问题 一、死锁问题&#xff1a; 因为每个客户端在设置锁过期时间时可能出现网络延迟等原因&#xff0c;有可能出现某个…

五项热门技术领域和应用场景

介绍五种当下比较热门的技术&#xff0c;分别是人工智能、云计算、数据分析、微服务和区块链。每种技术都有自己的定义、子领域、应用场景和学习难度。这些技术都有着广阔的发展前景和市场需求&#xff0c;对于想要从事或了解这些领域的人来说&#xff0c;都是很有价值的知识。…

centos7安装nginx的三种方式~yum源,源码,Docker

目录 1.yum安装&#xff1a;Centos7源默认没有nginx 2.源码安装&#xff1a; 3.Docker安装&#xff1a; 1.yum安装&#xff1a;Centos7源默认没有nginx 配置yum源&#xff1a; wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo 查看nginx源&…

Vue中的路由导航

声明式路由导航 router官网-起步 声明式路由导航其实就是使用官方给的<router-link>路由导航标签直接进行路由跳转 <body> <div id"app"><!--<router-link>路由导航标签&#xff0c;用于找到path属性中url对应的组件&#xff0c;通过传入…

Spring的循环依赖

什么是循环依赖&#xff1f; 循环依赖其实就是循环引用&#xff0c;也就是两个或者两个以上的 bean 互相持有对方&#xff0c;最终形成闭环。比如 A 依赖于 B&#xff0c;B 依赖于 C&#xff0c;C 又依赖于 A。如下图&#xff1a; 注意&#xff0c;这里不是函数的循环调用&…

rk3568-rk809电池电量计

简介&#xff1a; RK809 集成在RK3568上的一个高性能的 PMIC&#xff08;(Power Management IC):电源管理集成电路&#xff09;&#xff0c;PMIC全称Power management integrated circuit&#xff0c;一般情况下是一颗独立于主控的芯片&#xff0c;集成了电源控制&#xff0c;电…

Nginx rewrite ——重写跳转

Nginx常见模块 http http块是Nginx服务器配置中的重要部分&#xff0c;代理、缓存和日志定义等绝大多数的功能和第三方模块的配置都可以放在这模块中。作用包括&#xff1a;文件引入、MIME-Type定义、日志自定义、是否使用sendfile传输文件、连接超时时间、单连接请求数上限等…

不讲废话普通人了解 ChatGPT——基础篇第一课

wx供重浩&#xff1a;创享日记 获取更多内容 文章目录 前言什么是 ChatGPT它是如何工作的ChatGPT 和其它机器人有什么不同 前言 不知道大家在第一次会使用 ChatGPT 并尝试和他对话时有没有感到震惊。当ChatGPT首次推出时&#xff0c;我立即被它的功能所吸引。 曾经在遇到繁杂…

设计模式 -- 装饰模式

前言 月是一轮明镜,晶莹剔透,代表着一张白纸(啥也不懂) 央是一片海洋,海乃百川,代表着一块海绵(吸纳万物) 泽是一柄利剑,千锤百炼,代表着千百锤炼(输入输出) 月央泽,学习的一种过程,从白纸->吸收各种知识->不断输入输出变成自己的内容 希望大家一起坚持这个过程,也同…

【通知】CSDN学院:<华为流程体系课程> 正式上线啦!

目录 前言 适用人群 你将收获 课程介绍 前言 经过两个月的准备和短视频测试&#xff0c;这门介绍华为流程体系的课程就正式上线了。 虽然由于公开的原因&#xff0c;华为的发展受到了一定程度的影响&#xff0c;但是丝毫不妨碍企业、以及一些个人对学习华为的热情。 原因…

Qt扫盲-QAbstractSeries理论总结

QAbstractSeries理论总结 一、概述二、常用函数1. 属性2. 设置功能3. 显示隐藏4. 与 绘图的交互 三、信号 一、概述 QAbstractSeries类是所有Qt图表线的基类。通常&#xff0c;特定于序列类型的继承类会被使用&#xff0c;而不是这个基类。这个基类只是提供了一些管理和控制这…

使用Swagger生成在线文档

目录 1&#xff1a;Swagger介绍 2&#xff1a;使用 2.1&#xff1a;swaager集成boot依赖 2.2&#xff1a;配置文件中配置相关信息 2.3&#xff1a;在启动类中加入相关注解 2.4&#xff1a;测试 3&#xff1a;swagger常用注解 1&#xff1a;Swagger介绍 在前后端分离开发…

【华为OD机试 2023最新 】最大利润(C语言题解 )

文章目录 题目描述输入描述输出描述用例题目解析C语言题目描述 商人经营一家店铺,有number种商品, 由于仓库限制每件商品的最大持有数量是item[index] 每种商品的价格是item-price[item_index][day] 通过对商品的买进和卖出获取利润 请给出商人在days天内能获取的最大的利润…

系统可用性——冗余就够了吗?

导言 为了提高系统的可用性&#xff0c;如今很多集成商都号称采用了冗余设备来满足客户需求&#xff0c;乍一看产品性能提高不少。当我们再回顾其产品时&#xff0c;不禁要思考两个问题&#xff1a; 系统真的做到冗余了吗&#xff1f;仅仅使用冗余就够了吗&#xff1f; 回答…

量子力学、波函数与量子计算:揭开宇宙微观奥秘的神奇之门

在一个遥远的星球&#xff0c;生活着一群拥有超自然力量的智慧生物。他们能够随心所欲地让物体在空间瞬移&#xff0c;甚至能够预测未来。有一天&#xff0c;一位地球科学家意外穿越到了这个星球。经过一番了解&#xff0c;科学家惊奇地发现&#xff0c;他们所掌握的这种神奇力…