学习Spring的第二天

一  增强类型扩展

1.异常抛出增强

在Spring框架中,异常抛出增强是指通过AOP(面向切面编程)技术来增强方法的异常处理能力。当我们使用Spring框架进行开发时,可以利用AOP将一些通用的异常处理逻辑抽离出来,使得代码更加模块化和可维护。

在Spring中,异常抛出增强主要通过两种方式实现:

  1. 使用@AfterThrowing注解:通过在方法上添加@AfterThrowing注解,可以指定一个方法,在目标方法抛出异常后被执行。这个方法可以包含自定义的异常处理逻辑,比如记录日志、发送告警等。示例代码如下:
    @Aspect
    @Component
    public class ExceptionHandlerAspect {
        
        @AfterThrowing(pointcut = "execution(* com.example.service.*.*(..))", throwing = "ex")
        public void handleException(Exception ex) {
            // 异常处理逻辑
            System.out.println("捕获到异常:" + ex.getMessage());
        }
    }
    

    上述代码中,@AfterThrowing注解定义了切点表达式,指定了需要增强的方法范围;throwing属性指定了异常的类型,即只有抛出该类型的异常才会触发增强。在handleException方法中我们可以编写自己的异常处理逻辑。

  2. 通过实现ThrowsAdvice接口:除了使用注解方式外,还可以自定义一个类,并实现org.springframework.aop.ThrowsAdvice接口来处理异常。示例代码如下:
    public class ExceptionHandlerAdvice implements ThrowsAdvice {
        
        public void afterThrowing(Method method, Object[] args, Object target, Exception ex) {
            // 异常处理逻辑
            System.out.println("捕获到异常:" + ex.getMessage());
        }
    }
    

上述代码中,通过实现ThrowsAdvice接口,并定义afterThrowing方法来处理异常。在该方法中可以编写自己的异常处理逻辑。需要注意的是,方法参数中的Method对象表示抛出异常的方法,args数组表示方法的参数,target表示目标对象,ex表示抛出的异常。

无论是使用注解方式还是实现ThrowsAdvice接口,它们都能够增强Spring中的异常处理能力,使得我们能够更加灵活地对异常进行处理,提高系统的健壮性和可维护性。

 2.最终增强

在Spring框架中,最终增强是一种AOP(面向切面编程)技术,用于在目标方法执行后执行一些额外的操作。最终增强通常用于释放资源、进行清理操作或者记录日志等。

在Spring中,最终增强可以通过以下两种方式实现:

  1. 使用@After注解:通过在方法上添加@After注解,可以指定一个方法,在目标方法执行完成后被执行。该方法无论目标方法是否抛出异常都会被执行。示例代码如下:
    @Aspect
    @Component
    public class FinalizeAspect {
        
        @After("execution(* com.example.service.*.*(..))")
        public void afterMethod() {
            // 最终增强逻辑
            System.out.println("目标方法执行完成后的最终增强");
        }
    }
    

    上述代码中,@After注解定义了切点表达式,指定了需要增强的方法范围。在afterMethod方法中我们可以编写自己的最终增强逻辑。

  2. 实现MethodInterceptor接口:除了使用注解方式外,还可以自定义一个类,并实现org.aopalliance.intercept.MethodInterceptor接口来处理最终增强。示例代码如下:
    public class FinalizeInterceptor implements MethodInterceptor {
        
        @Override
        public Object invoke(MethodInvocation methodInvocation) throws Throwable {
            // 目标方法执行前的逻辑
            Object result = methodInvocation.proceed();
            // 目标方法执行后的最终增强逻辑
            System.out.println("目标方法执行完成后的最终增强");
            return result;
        }
    }
    

上述代码中,我们实现了MethodInterceptor接口,并重写了其中的invoke方法。在该方法中,可以编写目标方法执行前的逻辑,然后调用methodInvocation.proceed()执行目标方法,最后编写目标方法执行后的最终增强逻辑。

无论是使用注解方式还是实现MethodInterceptor接口,它们都能够在目标方法执行完成后执行一些额外的操作,提供更多的灵活性和可扩展性。通过最终增强,我们可以进行资源释放、清理操作或者记录日志等常见的后置处理操作。

 3.环绕增强

在Spring框架中,环绕增强是一种AOP(面向切面编程)技术,用于在目标方法执行前后都执行一些额外的操作。通过环绕增强,我们可以完全控制目标方法的执行过程,包括执行前、执行中以及执行后的逻辑。

在Spring中,环绕增强可以通过以下方式实现:

  1. 使用@Around注解:通过在方法上添加@Around注解,可以指定一个方法,在目标方法执行前后被执行。在方法体内部,需要调用ProceedingJoinPoint.proceed()方法来手动触发目标方法的执行,并可以在执行前后进行自定义逻辑处理。示例代码如下:
    @Aspect
    @Component
    public class AroundAdvice {
        
        @Around("execution(* com.example.service.*.*(..))")
        public Object aroundMethod(ProceedingJoinPoint joinPoint) throws Throwable {
            // 目标方法执行前的逻辑
            System.out.println("目标方法执行前的环绕增强");
            
            // 执行目标方法
            Object result = joinPoint.proceed();
            
            // 目标方法执行后的逻辑
            System.out.println("目标方法执行后的环绕增强");
    
            return result;
        }
    }
    

    上述代码中,@Around注解定义了切点表达式,指定了需要增强的方法范围。在aroundMethod方法中,我们可以编写自己的环绕增强逻辑。通过调用joinPoint.proceed()方法来手动触发目标方法的执行,并可以在执行前后进行自定义逻辑处理。

  2. 实现MethodInterceptor接口:除了使用注解方式外,还可以自定义一个类,并实现org.aopalliance.intercept.MethodInterceptor接口来处理环绕增强。示例代码如下:
    public class AroundInterceptor implements MethodInterceptor {
        
        @Override
        public Object invoke(MethodInvocation methodInvocation) throws Throwable {
            // 目标方法执行前的逻辑
            System.out.println("目标方法执行前的环绕增强");
            
            // 执行目标方法
            Object result = methodInvocation.proceed();
            
            // 目标方法执行后的逻辑
            System.out.println("目标方法执行后的环绕增强");
    
            return result;
        }
    }
    

上述代码中,我们实现了MethodInterceptor接口,并重写了其中的invoke方法。在该方法中,可以编写目标方法执行前的逻辑,然后调用methodInvocation.proceed()方法执行目标方法,最后编写目标方法执行后的逻辑。

无论是使用注解方式还是实现MethodInterceptor接口,它们都能够在目标方法执行前后执行一些额外的操作,提供更大的灵活性和控制力。通过环绕增强,我们可以对目标方法的执行过程进行完全的控制和定制化处理。

 二  依赖注入方式扩展

1.构造注入

在Spring框架中,构造注入是一种依赖注入的方式,通过构造函数来注入依赖对象。相比于其他的注入方式(如Setter注入),构造注入更加推荐使用,因为它能够确保依赖对象在创建时就被注入,使得对象的状态更加可靠和不可变。

在进行构造注入时,需要遵循以下步骤:

1.在目标类中定义一个带有依赖参数的构造函数。构造函数的参数应该与所需注入的依赖对象类型相匹配。示例代码如下:

public class Foo {
    private Bar bar;
    
    public Foo(Bar bar) {
        this.bar = bar;
    }
    
    // 其他方法...
}

上述代码中,Foo类定义了一个带有Bar类型参数的构造函数,用于接收Bar对象作为依赖。

2.在Spring配置文件中进行配置,将依赖对象注入到目标类中。可以使用XML配置方式或者基于Java的配置方式。示例代码如下:

XML配置方式:

<bean id="fooBean" class="com.example.Foo">
    <constructor-arg ref="barBean"/>
</bean>

<bean id="barBean" class="com.example.Bar"/>

Java配置方式:

@Configuration
public class AppConfig {
    
    @Bean
    public Foo foo() {
        return new Foo(bar());
    }
    
    @Bean
    public Bar bar() {
        return new Bar();
    }
}

上述代码中,通过<constructor-arg>元素或者在Java配置中的构造函数调用来指定要注入的依赖对象。

3.在需要使用目标类的地方,通过Spring容器获取已经注入依赖后的实例。示例代码如下:

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Foo foo = (Foo) context.getBean("fooBean");

上述代码中,通过context.getBean()方法从Spring容器中获取已经注入依赖后的Foo对象。

通过以上步骤,就可以实现构造注入方式来注入依赖对象。构造注入能够提供更好的对象可靠性和不变性,并且使得代码更具可测试性和扩展性。

2.p命名注入

在Spring框架中,p命名空间注入是一种XML配置方式,用于进行属性的依赖注入。通过p命名空间注入,我们可以简化配置文件的书写,提高可读性和维护性。

使用p命名空间注入时,需要按照以下步骤进行配置:

  1. 在XML配置文件中引入p命名空间,示例代码如下:
    <beans xmlns:p="http://www.springframework.org/schema/p"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="
                http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                http://www.springframework.org/schema/p http://www.springframework.org/schema/p/spring-p.xsd">
    
    <!-- 配置bean -->
    
    </beans>
    

    上述代码中,通过xmlns:p声明了p命名空间,并在xsi:schemaLocation中指定了对应的schema文件。

  2. 针对要注入属性的bean,使用p命名空间进行配置。示例代码如下:
    <bean id="fooBean" class="com.example.Foo" p:name="John" p:age="25"/>
    

    上述代码中,通过使用p命名空间为Foo类的对象fooBean注入了nameage属性。

  3. 如果属性是引用类型,则可以使用p命名空间的ref属性来指定引用的bean。示例代码如下:
    <bean id="fooBean" class="com.example.Foo" p:bar-ref="barBean"/>
    <bean id="barBean" class="com.example.Bar"/>
    

    上述代码中,通过p:bar-ref属性将fooBeanbar属性注入了barBean

通过以上配置,就可以使用p命名空间进行属性的依赖注入。p命名空间注入方式简化了配置文件的书写,提高了可读性和维护性,尤其适用于只有少量属性需要注入的情况。但需要注意的是,p命名空间注入仅支持基本数据类型和引用类型的注入,并且对于复杂的依赖关系,还是推荐使用其他的注入方式,如构造注入或Setter注入。

3.不同数据类型的注入 

在Spring框架中,可以对不同的数据类型进行依赖注入。Spring提供了多种方式来注入不同类型的数据,包括基本数据类型、引用类型(其他Bean)、集合类型等。

下面是Spring中常见的数据类型注入方式:

1.基本数据类型注入:可以通过XML配置或注解方式将基本数据类型的值直接注入到Bean中。示例代码如下:

XML配置方式:

<bean id="exampleBean" class="com.example.ExampleBean">
    <property name="age" value="25" />
</bean>

 注解方式:

@Component
public class ExampleBean {
    @Value("25")
    private int age;
}

2.引用类型注入:可以将一个Bean注入到另一个Bean中,通过构造函数注入或Setter方法注入。示例代码如下:

构造函数注入:

<bean id="fooBean" class="com.example.Foo">
    <constructor-arg ref="barBean"/>
</bean>

<bean id="barBean" class="com.example.Bar"/>

Setter方法注入:

<bean id="fooBean" class="com.example.Foo">
    <property name="bar" ref="barBean"/>
</bean>

<bean id="barBean" class="com.example.Bar"/>

Setter方法注入:

<bean id="fooBean" class="com.example.Foo">
    <property name="bar" ref="barBean"/>
</bean>

<bean id="barBean" class="com.example.Bar"/>

3.集合类型注入:可以注入List、Set、Map等集合类型的数据。示例代码如下:

List注入:

<bean id="exampleBean" class="com.example.ExampleBean">
    <property name="names">
        <list>
            <value>Tom</value>
            <value>Jerry</value>
        </list>
    </property>
</bean>

 Set注入:

<bean id="exampleBean" class="com.example.ExampleBean">
    <property name="names">
        <set>
            <value>Apple</value>
            <value>Banana</value>
        </set>
    </property>
</bean>

Map注入:

<bean id="exampleBean" class="com.example.ExampleBean">
    <property name="students">
        <map>
            <entry key="1" value="Tom"/>
            <entry key="2" value="Jerry"/>
        </map>
    </property>
</bean>

上只是展示了一些常见的数据类型注入方式,Spring还支持其他更多复杂的注入方式,如数组注入、Properties注入等。选择适当的注入方式取决于具体的需求和场景。

三  使用注解实现Spring  IoC

在Spring框架中,可以使用注解来实现IoC(控制反转)操作,即通过注解方式告诉Spring容器如何管理Bean的创建和依赖关系。下面是几个常用的注解:

  1. @Component:用于标记一个类为Spring的组件,通常用于自动扫描组件并将其注册到Spring容器中。示例代码如下:
    @Component
    public class ExampleComponent {
        // 类的实现...
    }
    
  2. @Autowired:用于自动注入依赖对象。当一个Bean需要依赖其他Bean时,可以使用@Autowired注解标记在字段、构造函数或Setter方法上,Spring会自动查找匹配的Bean进行注入。示例代码如下:
    @Component
    public class ExampleBean {
        @Autowired
        private ExampleDependency exampleDependency;
        
        // 其他方法...
    }
    
  3. @Qualifier:与@Autowired一起使用,用于指定具体的Bean进行注入。当存在多个类型兼容的Bean时,可以使用@Qualifier注解指定具体的Bean名称进行注入。示例代码如下:
    @Component
    public class ExampleBean {
        @Autowired
        @Qualifier("specificDependency")
        private ExampleDependency exampleDependency;
        
        // 其他方法...
    }
    
    @Component("specificDependency")
    public class SpecificDependency implements ExampleDependency {
        // 类的实现...
    }
    
  4. @Value:用于将值注入到Bean的属性中。可以通过@Value注解直接注入常量值,也可以通过SpEL(Spring表达式语言)注入动态值。示例代码如下:
    @Component
    public class ExampleBean {
        @Value("25")
        private int age;
        
        @Value("${app.name}")
        private String appName;
        
        // 其他方法...
    }
    

在上述代码中,@Value注解将值"25"注入到age属性中,${app.name}表示从配置文件中读取名为app.name的属性值。

除了上述注解,Spring还提供了许多其他的注解,如@Service@Repository@Controller等用于标记不同类型的组件,以及@Scope@PostConstruct@PreDestroy等用于管理Bean的作用域和生命周期。

使用注解实现Spring IoC具有简洁、便捷的特点,能够减少配置的工作量,并提高代码的可读性和维护性。然而,需要注意合理使用注解,避免过度使用导致代码可读性降低。

 四  使用注解实现 Spring AOP

在Spring框架中,可以使用注解方式实现AOP(面向切面编程)。通过注解,我们可以方便地定义切点、切面以及通知等关键部分。

下面是使用注解实现Spring AOP的步骤:

  1. 引入相关的依赖: 首先,在项目的构建文件(如Maven)中引入相关的依赖,包括spring-aop和其他所需的Spring模块。

  2. 定义切面类: 创建一个类并使用@Aspect注解标记为切面类。切面类包含各种通知(Advice)和切点定义。

    @Aspect
    @Component
    public class LoggingAspect {
        // 切点定义
        @Pointcut("execution(* com.example.service.*.*(..))")
        private void serviceMethods() {}
    
        // 前置通知
        @Before("serviceMethods()")
        public void beforeAdvice(JoinPoint joinPoint) {
            // 执行前置逻辑
        }
    
        // 后置通知
        @AfterReturning(pointcut = "serviceMethods()", returning = "result")
        public void afterReturningAdvice(JoinPoint joinPoint, Object result) {
            // 执行后置逻辑
        }
    
        // 异常通知
        @AfterThrowing(pointcut = "serviceMethods()", throwing = "ex")
        public void afterThrowingAdvice(JoinPoint joinPoint, Exception ex) {
            // 处理异常逻辑
        }
    
        // 环绕通知
        @Around("serviceMethods()")
        public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
            // 执行前置逻辑
            Object result = joinPoint.proceed();
            // 执行后置逻辑
            return result;
        }
    }
    
  3. 配置Spring AOP: 在Spring配置文件中启用AOP,并将切面类注册到Spring容器中。
    <aop:aspectj-autoproxy />
    
    <bean id="loggingAspect" class="com.example.aspect.LoggingAspect" />
    

以上代码中,LoggingAspect类使用了@Aspect注解标记为切面类,定义了各种通知(Advice),如前置通知(@Before)、后置通知(@AfterReturning)、异常通知(@AfterThrowing)和环绕通知(@Around)。通过@Pointcut注解定义了切点,指定了需要被通知的方法。

在配置文件中,通过<aop:aspectj-autoproxy />开启了基于AspectJ的自动代理功能,并将切面类LoggingAspect注册为一个Bean。

使用注解实现Spring AOP简化了配置文件的编写,使得切面的定义更加直观和灵活。同时,可以根据实际需求选择不同类型的通知和切点表达式,实现细粒度的控制和扩展。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值