Spring学习——【初识注解】

8 篇文章 0 订阅
3 篇文章 0 订阅

初识注解:

①@ComponentScan:组件扫描

@ComponentScan在AppConfig.class中的四种写法:
    ①直接写@ComponentScan:意为扫描AppConfig.class所在的包以及所有子包中含有@Component注解的类并注册Bean。
    ②写一个包@ComponentScan("com.zzx.demo"):意为扫描指定包以及指定包的所有子包中含有@Component注解的类并注册Bean。
    ③写多个包@ComponentScan(basePackages = {"com.zzx.demo.web","com.zzx.demo.service","com.zzx.demo.dao"}):
	意为扫描多个包以及这多个包的所有子包中含有@Component注解的类并注册Bean。
    ④写类@ComponentScan(basePackageClasses = {UserController.class, UserService.class, UserDao.class}):
	意为扫描类所在的包以及类所在的包的所有子包中含有含有@Component注解的类并注册Bean。

 


AppConfig.class:

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@ContextConfiguration
@ComponentScan("com.zzx.demo")
public class AppConfig {
}

@Configuration:意为标注当前类是一个配置类。

  ②@Conponent:标注其是一个组件

@Component:
    可以写为@Component("类id"),在里面写着的是标识当前类的类id,如果不写,则默认为当前类名的首字母小写的字符串是类id,例如:当前类为UserServiceNormal,则类id为:userServiceNormal。
    该组件等同于在applicationContext.xml中的:
       <bean id="userServiceNormal" class="com.zzx.demo.service.impl.UserServiceNormal"/>

@Controller
@Service
@Repository
这三个注解的本质与@Component是一样的,只是语义上更加明确了,明确的表示了当前的类在应用程序的哪个层次,扮演了什么样的功能。
同样的,它们也可以由程序员来写出当前类的‘类id’来标识当前类。

③@Autowired:自动装配

 *      @Autowired四种使用场景:
 *          1.给成员变量【最便捷】
 *          2.给成员变量的setter方法
 *          3.给有参构造函数【效率最高】
 *          4.给任意方法

//1.给成员变量
@Component
public class CDPlayer {
    @Autowired
    private CompactDisc cd;
    @Autowired
    private Power power;
    public CDPlayer() {
        super();
        System.out.println("CDPlayer无参构造函数~");
    }
    public void play(){
        power.supply();
        cd.play();
    }
}
//2.给成员变量的setter方法
@Component
public class CDPlayer {
    private CompactDisc cd;
    private Power power;
    @Autowired
    public void setCd(CompactDisc cd) {
        this.cd = cd;
        System.out.println("调用setCd……");
    }
    @Autowired
    public void setPower(Power power) {
        this.power = power;
        System.out.println("调用setPower……");
    }
    public CDPlayer() {
        super();
        System.out.println("CDPlayer无参构造函数~");
    }
    public void play(){
        power.supply();
        cd.play();
    }
}
//3.给有参构造函数
@Component
public class CDPlayer {
    private CompactDisc cd;
    private Power power;
    public CDPlayer() {
        super();
        System.out.println("CDPlayer无参构造函数~");
    }
    @Autowired//将构造函数的参数自动装配到当前的类中
    public CDPlayer(CompactDisc cd) {
        this.cd = cd;
        System.out.println("CDPlayer有参构造函数~");
    }
    @Autowired
    public CDPlayer(CompactDisc cd, Power power) {
        this.cd = cd;
        this.power = power;
        System.out.println("CDPlayer的多参数函数构造方法......");
    }
    public void play(){
        power.supply();
        cd.play();
    }
}
//4.给给任意方法
@Component
public class CDPlayer {
    private CompactDisc cd;
    private Power power;
    public CDPlayer() {
        super();
        System.out.println("CDPlayer无参构造函数~");
    }
    @Autowired
    public void prepare(CompactDisc cd , Power power){
        this.cd = cd;
        this.power = power;
        System.out.println("prepare方法被调用……");
    }
    public void play(){
        power.supply();
        cd.play();
    }
}

//@Autowired的默认属性为required = true,意为必须能被spring找到,而如果那个类没有@Component注解,则不能被找到。
//如果将默认属性改为required = false,那么spring容器如果找不到的话,也不会出现错误。
//后接最下方if语句后面的注释
//例如:


//@Component
public class CompactDisc {
    public CompactDisc() {
        super();
        System.out.println("CompactDisc无参构造函数~");
    }
    public void play(){
        System.out.println("正在播放音乐!");
    }
}


@Component
public class CDPlayer {
    @Autowired(required = false)
    private CompactDisc cd;
    @Autowired
    private Power power;
    public CDPlayer() {
        super();
        System.out.println("CDPlayer无参构造函数~");
    }
    public void play(){
        power.supply();
        if (cd != null) {    //那么相对应的此处,就要判断spring容器是否找到对应的类,能否创建出来对象
            cd.play();
        }
    }
}


 ④@RunWith和@ContextConfiguration

//在pom.xml文件中,引入spring-test模块,就可以使用这两个注释:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AppConfig.class)//有了这两个注解,这个ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);就可以省略了
public class AppTest {
    @Autowired//再搭配自动注入,可以把CDPlayer player = context.getBean(CDPlayer.class);也省略了,这样test方法中就只留下player.play();
    private CDPlayer player;
    @Test
    public void testPlay(){
        player.play();
    }
}

⑤自动装配的歧义性:

//当有一个接口,同时有两个或多个实现类的时候,自动装配就会产生歧义性,它会不知道装配哪一个实现类
//比如对于UserService.interface这个接口,同时有UserServiceNormal.class和UserServiceFestival.class这两个实现类,而在UserController.class中:
@Controller
public class UserController {
    @Autowired
    private UserService userService;
    public void add(){
        userService.add();
    }
}
//使用了@Autowired,那么如果你使用idea,这个时候private UserService userService;下面就会产生一条红色波浪线,提示你不能Autowired。
//这个地方就是因为自动装配的歧义性,它不知道该使用两者中的哪一个。


//解决方法:
//1.给某一个实现类加一个注解@Primary,此时那条红线就会消失,因为它知道了去装配哪个,首选你注解了@Primary的那个实现类(有些时候不太适合,有一定的局限性)
//2.标识实现类的类id,并在自动装配@Autowired的地方加一个注解@Qualifier,例如:@Qualifier("userServiceFestival"),它就会装配UserServiceFestival.class这个实现类
//3.将UserService改为UserServiceNormal或者UserServiceFestival即可,例如:private UserServiceNormal userServiceNormal;(不推荐)
//4.使用@Resource注解代替@Autowired和@Qualifier,例如:@Resource(name="userServiceFestival")。

//重新总结一下解决方法:
/*      解决方法:
 *          1.将UserService改为UserServiceNormal或者UserServiceFestival即可(不推荐)
 *          2.使用首选Bean,在某个实现类上使用@Primary注解,将其设置为首选(有些时候不太适合,有一定的局限性)
 *          3.使用限定符,即@Qualifier这个注解,使用限定符要和在实现类里的@Qualifier中的字符串一致,匹配后就会使用对应的实现类
 *          4.使用限定符和类id,即在实现类通过@Component("id")为实现类设置id,在使用的时候,@Qualifier注解也可以通过@Component中的id来匹配
 *          5.使用限定符和类id,即@Component不写id,spring会默认将实现类的类名(首字母小写)作为类id,其余同上
 *          6.使用@Resource注解,可以同时代替@Autowired和@Qualifier("userServiceFestival")这两个注解(jdk的标准),注解中的name对应类id
 */

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring AOP是Spring框架中的一个重要模块,它提供了面向切面编程(AOP)的支持。AOP是一种编程思想,它可以在不改变原有代码的情况下,通过在程序运行时动态地将代码“织入”到现有代码中,从而实现对原有代码的增强。 Spring AOP提供了基于注解的AOP实现,使得开发者可以通过注解的方式来定义切面、切点和通知等相关内容,从而简化了AOP的使用。 下面是一个基于注解的AOP实现的例子: 1. 定义切面类 ```java @Aspect @Component public class LogAspect { @Pointcut("@annotation(Log)") public void logPointcut() {} @Before("logPointcut()") public void beforeLog(JoinPoint joinPoint) { // 前置通知 System.out.println("执行方法:" + joinPoint.getSignature().getName()); } @AfterReturning("logPointcut()") public void afterLog(JoinPoint joinPoint) { // 后置通知 System.out.println("方法执行完成:" + joinPoint.getSignature().getName()); } @AfterThrowing(pointcut = "logPointcut()", throwing = "ex") public void afterThrowingLog(JoinPoint joinPoint, Exception ex) { // 异常通知 System.out.println("方法执行异常:" + joinPoint.getSignature().getName() + ",异常信息:" + ex.getMessage()); } } ``` 2. 定义业务逻辑类 ```java @Service public class UserService { @Log public void addUser(User user) { // 添加用户 System.out.println("添加用户:" + user.getName()); } @Log public void deleteUser(String userId) { // 删除用户 System.out.println("删除用户:" + userId); throw new RuntimeException("删除用户异常"); } } ``` 3. 在配置文件中开启AOP ```xml <aop:aspectj-autoproxy/> <context:component-scan base-package="com.example"/> ``` 在这个例子中,我们定义了一个切面类LogAspect,其中通过@Aspect注解定义了一个切面,通过@Pointcut注解定义了一个切点,通过@Before、@AfterReturning和@AfterThrowing注解分别定义了前置通知、后置通知和异常通知。 在业务逻辑类中,我们通过@Log注解标注了需要增强的方法。 最后,在配置文件中,我们通过<aop:aspectj-autoproxy/>开启了AOP功能,并通过<context:component-scan>扫描了指定包下的所有组件。 这样,当我们调用UserService中的方法时,就会触发LogAspect中定义的通知,从而实现对原有代码的增强。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值