Spring避坑指南

本文概述了Java开发中使用Spring时遇到的四个主要问题:1)InitializingBean接口的初始化策略;2)Bean的注入,包括静态注入和SpEL注入;3)AOP中的代理对象获取和注意事项;4)@Service注解类不能直接继承的问题及其解决方案。
摘要由CSDN通过智能技术生成

总结一些Java日常开发中应用Spring踩过的坑,开发的时候要时刻注意。

一、Bean的一些使用

1、InitializingBean接口使用理解

总结:

  • spring为bean提供了两种初始化bean的方式,实现InitializingBean接口,实现afterPropertiesSet方法,或者在配置文件中同过init-method指定,两种方式可以同时使用;

  • 实现InitializingBean接口是直接调用afterPropertiesSet方法,比通过反射调用init-method指定的方法效率相对来说要高点。但是init-method方式消除了对spring的依赖;

  • 如果调用afterPropertiesSet方法时出错,则不调用init-method指定的方法。

2、Bean的注入

InitializingBean,postconstruct

3、关于静态注入

@Value("#{T(java.lang.Math).random()}")
private double randomValue;

@Autowired
@Qualifier("#{T(java.util.Arrays).asList('beanA', 'beanB')}")
private List<BeanType> beanList;
  • static变量使用@Autowired,会抛出运行时异常java.lang.NullPointerException,因为spring则是基于对象层面上的依赖注入;

  • 实现静态注入的三种方法:

方法

说明

xml方式实现

使用xml注入

@PostConstruct方式实现

@PostConstruct 在加载类的构造函数之后执行,也就是在加载了构造函数之后,执行init方法;(@PreDestroy 注解定义容器销毁之前的所做的操作)

这种方式和在xml中配置 init-method和 destory-method方法差不多,定义spring 容器在初始化bean 和容器销毁之前的所做的操作;

set方法注入

通过setter方法注入

4、使用SpEL实现集合注入

  • 使用SpEL(Spring Expression Language)实现注入,例如:

@Value("#{T(java.lang.Math).random()}")
private double randomValue;

@Autowired
@Qualifier("#{T(java.util.Arrays).asList('beanA', 'beanB')}")
private List<BeanType> beanList;

二、AOP

1、AOP对象内部想拿到自己的proxy对象

1.1 使用AopContext.currentProxy()

  • 可以使用AopContext.currentProxy()方法来获取当前对象的代理对象。但是需要注意的是,这种方式只适用于使用Spring AOP框架的情况下。

@Autowired
private AopContext aopContext;

public void someMethod() {
    MyObject proxy = (MyObject) aopContext.currentProxy();
    // 使用代理对象进行操作
}
  • 配置exposeProxy = true:

// 加在配置类上,或者启动类上也行
@Configuration
@EnableAspectJAutoProxy(exposeProxy = true)
public class AppConfig {
    // ...
}

1.2 使用AspectJ时

  • 在使用AspectJ时,可以通过org.aspectj.lang.reflect.AdviceSignature对象获取到当前Advice的信息,但无法直接获取到代理对象。如果需要在AspectJ中获取代理对象,可以使用this()或target()表达式来获取当前对象或目标对象的引用,然后进行类型转换。例如:

@Aspect
public class MyAspect {
  
  @Before("execution(* com.example.MyService.*(..))")
  public void before(JoinPoint joinPoint) {
    MyService target = (MyService) joinPoint.getTarget();
    // 使用target对象进行操作
  }
  
}
  • target()表达式只能在execution()切点表达式中使用,而无法在其他类型的切点表达式中使用。

1.3 小心踩坑

  • 一些应用场景:对于某些通过注解实现的加锁方法,如果在同类的内部调用中,没有获取当前类的代理,会导致加锁不生效;

2、用@service注解的类不能使用extends关键字

  • 使用@Service注解的类若继承了另一个类,此时自动装配@Autowired和@Resource均无法正确装配bean,抛出org.springframework.beans.factory.BeanNotOfRequiredTypeException异常。

  • AOP的源码中用到了两种动态代理来实现拦截切入功能:jdk动态代理和cglib动态代理。其中jdk动态代理只支持接口注入,不支持类注入;要想实现基于类的代理,需要引入cglib库。

    解决方案:定义接口类ServiceInterface,ServiceImp实现ServiceInterface接口,自动装配时使用接口类来接收ServiceImp,实现接口注入。

  • 13
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值