目录
十一、Lombok
十二、基于注解方式的IoC
十一、Lombok
在上面的课程讲解过程中,每次修改类的属性,都需要重新生成Getter/Setter方法及toString()方法。我 们可以借助Lombok来简化代码。
1 环境准备
下载Lombok插件
IDEA 2022.3.2 默认集成Lombok插件,不需要单独下载。而且Lombok插件是不允许被卸载的。
启用注解处理
不启用注解处理,也能正常出结果。只是在第一次启动后,会在IDEA右下角提示,请启用注解处理。
IDEA菜单 File -> Settings
2. @Data
Lombok支持的注解比较多,可以从Lombok插件看到所有支持的注解。
我们挑选出一些常用的注解,先来看看@Data注解
在类上添加@Data注解
@Data
public class Person {
private String name;
private int age;
}
测试生成的方法
可以使用属性的getter/setter方法。并且进入equals和hashCode()和toString()时是进入到Person类。 而去掉@Data注解时是进入到Object类中,说明@Data也生成equals()和hashCode()和toString()方法。
@Test
void testLombok(){
Person p1 = new Person();
p1.setName("smallming");
p1.setAge(18);
p1.getAge();
p1.getName();
p1.equals("");
p1.hashCode();
p1.toString();
}
3. 构造方法处理
默认情况下使用无参构造方法。但是Lombok支持3个对构造方法处理的注解。这三个注解只要使用任意 一个,将不会在有默认的无参构造方法
3.1、@NoArgsConstructor :生成无参数构造方法
3.2、@AllArgsConstructor:生成全参构造方法
3.3、@RequiredArgsConstructor:生成一个包含所有final和 @NonNull属性的构造方法。
4. Getter和Setter处理
@Getter和@Setter是类和属性注解。可以用在类上表示给所有属性都生成。如果用在某个属性上,表示 只给这个属性生成。
4.1、@Getter 给属性生成getter方法
4.2、@Setter 给属性生成setter方法
5. @ToString
给类生成包含所有属性的toString()方法,除非属性上包含@ToString.Exclude
6. 日志注解
Lombok支持市面上绝大多数日志。只需要在项目中引入对应日志的依赖。然后就可以在类中直接使用 log对象。
不同的日志类型区别也就是log对象的类型不同:
@Log 原生JDK日志。类型:java.util.logging.Logger
@Log4j apache的日志。类型:org.apache.log4j.Logger
@Log4j2 apache的日志。类型:org.apache.logging.log4j.Logger
@Slf4j 类型:org.slf4j.Logger
@XSlf4j 类型:org.slf4j.ext.XLogger
@CommonsLog apache的日志。类型:org.apache.commons.logging.Log @JBossLog jboss的日志。类型:org.jboss.logging.Logger
@Flogger 谷歌的日志。类型:com.google.common.flogger.FluentLogger
@CustomLog 自定义日志。类型:自定义的日志类型。
使用时需要导入对应日志依赖。以log4j2举例。在项目中引入
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.20.0</version>
</dependency>
在类中使用log对象(无论哪种日志类型),不再需要实例化。
@Data
@Log4j2
public class Person {
private String name;
private int age;
public void test(){
// 直接使用log对象,不需要实例化
log.info("日志信息");
}
}
十二、基于注解方式的IoC
1.为什么要学习注解方式的IoC
无论什么技术,什么框架。只要是同一个技术即提供了XML配置方式,又提供了注解方式。注解方式都是为了简化XML配置,让代码编写变得更加简单。
2.Spring Framework如何开启注解支持
注解不是写上就生效的。我们需要告诉Spring Framework哪里有注解。这样Spring框架就会去这个包及子包去寻找注解。然后(通过反射)解析注解。
在Spring框架配置文件添加context命名空间及xsd文件路径。并使用标签配置需要Spring框架扫描哪个包及所有子包的注解。
<?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:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.tong"></context:component-scan>
</beans>
3.让IoC容器实例化类对象的注解
类中注解想要生效,前提是当前类的Bean被IoC容器管理。所以我们先来学习下如何让IoC容器实例化类。
@Component注解
我们先来回顾下使用XML方式对类进行实例化的方式。
配置时只有两处:
1、Bean在IoC容器中的名称
2、类的全限定路径
而使用注解时,只需要把注解放在类上,就知道了类的权限定路径。也就是说使用注解只需要配置下 Bean在IoC容器中的名称就可以了。
@Component注解就是负责告诉IoC容器,需要对当前类实例化的。
@Component注解里面只有value属性。value属性用于配置Bean的名称,可省略。
具体代码示例:
@Component(value="bean的名称")
//@Component("bean的名称") value可省略
//@Component 不写bean的名称时,bean的名称为类名首字母变小写,其他字母不变。
public class Person {
}
@Component注解的子注解
@Component注解一共有四个子注解。这四个子注解功能和@Component注解完全相同。唯一的区别 是语义上有区别。语义区别是指:为了方便程序员阅读代码,提升代码规范,不同类型的类上应该用不 同的注解。
@Repository :数据访问层,类上注解。常用在XXXDaoImpl类上。
@Service:业务层,类上注解。常用在XXXServiceImpl类上。
@Controller:控制层,类上注解。常用在XXXController类上。Spring MVC时控制器上注解。
@Configuration:配置类,类上注解。当使用Java类方式对Spring框架进行配置时使用。
@Component:不是以上情况时使用。
小提示: 这些注解没有功能上的区别,所以不按照上面位置去使用也能出效果。 但是为了提升代码规范,方便自己,方便他人,还是按照对应语义去使用会更好。
4.@Value注解
IoC容器内一般不放简单数据类型的Bean。所以类中属性如果是简单数据类型,在使用注解方式配置 Bean时,直接给属性赋予默认值就可以了。
@Component
@Data
public class Person {
/*
等效于:
<bean id="" class="">
<property name="name" value="smallming"></property>
</bean>
*/
private String name="smallming";
}
像这种简单数据类型,在Spring框架中唯一一种能见到的注入属性方式就是使用@Value注解。 @Value注解作用:
1、读取Spring容器中properties文件某个key对应的value值
2、对value值做类型转换,并赋值给属性中
根据上面作用可以看出来,我们首先必须要让IoC容器能读取一个properties文件。 假设:我们在src/main/resources下新建 test.properties文件,并在文件中添加二组键值对
然后在Spring配置文件中,告诉Spring框架去加载这个属性文件。
<context:property-placeholder location="test.properties"></context:property-placeholder>
如果不想使用配置文件方式,也可以在类上添加@PropertySource注解,来加载属性文件
@Component
@PropertySource("test.properties")
@Data
public class Person {
语法为:@Value("${ key 的名称 }") ,如果没有${}将表示固定字符串。
@Component
@Data
public class Person {
@Value("${mykey}")
String content;
@Value("${myage}")
int age; // 由Spring框架做类型转换
}
5.@Autowired 注解实现Bean注入
本小节内容其实就是注解方式实现如何把Bean注入到当前实例。
@Autowired功能是从IoC容器中把其他Bean注入进来。有以下特点:
1、必须保证当前类被IoC容器管理,无论是XML方式还是注解方式都可以。否则@Autowire无效。
2、默认按照byType注入,如果有多个相同类型按照属性名称byName注入。
3、如果属性名和IoC容器中Bean的名称不一致,可以结合@Qualifier注解一起使用
5.1 测试@Autowired效果
创建一个学生类,并放入到IoC容器中。
@Component
public class Student {}
创建一个老师类,类中包含学生属性。使用@Autowired注解注入
@Data
@Component
public class Teacher {
@Autowired
private Student stu;
}
测试效果
@Test
void annotion(){
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext-annotation.xml");
Teacher teacher = ac.getBean("teacher", Teacher.class);
System.out.println(teacher);
}
发现输出结果中,Teacher中stu属性已经被注入了。
5.2 测试@Autowired注入方式
在配置文件中再配置一个bean.(注:目前所学,使用注解没有办法给一个类配置两个Bean,只能结合 XML)
<bean id="stu2" class="com.tong.annotation.Student"></bean>
再次运行会报错。控制台提示,无法注入,希望有一个Student类型,但是发现了两个,分别叫做 student,stu2
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No
qualifying bean of type 'com.tong.annotation.Student' available: expected single
matching bean but found 2: student,stu2
at
org.springframework.beans.factory.config.DependencyDescriptor.resolveNotUnique(D
ependencyDescriptor.java:218)
at
org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDe
pendency(DefaultListableBeanFactory.java:1383)
at
org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDepe
ndency(DefaultListableBeanFactory.java:1325)
at
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcesso
r$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.j
ava:709)
... 86 more
如果修改Teacher中属性名为student或stu2,会发现又可以成功注入了。
5.3 测试@Qualifier注解
如果不希望Teacher中Student属性名和IoC容器中Bean的名称相同,可以使用@Qualifier注解指定需要 注入的Bean名称。
@Data
@Component
public class Teacher {
@Autowired
@Qualifier("stu2")
private Student stu;
}
6.@Resource注解实现Bean注入
@Resource注解是JPA中的注解,也能够实现注入属性的功能。JPA是Java EE规范中一项。所以JPA并没 有包含在JDK中,需要额外导入依赖。
所以在老版本Spring中想要使用@Resource注解,必须保证项目中包含依赖
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
从Java EE 8 开始Oracle把Java EE规范标准交给Eclipse基金会去维护,并更名为Jakarta EE。 Spring 6 默认使用Jakarta EE 9作为标准。所以在当前版本中需要添加jakarta.annotation-api依赖
<dependency>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
<version>2.1.1</version>
</dependency>
并且在使用时,需要导入的包由之前javax.annotation.Resource的换成jakarta.annotation.Resource
package com.tong.annotation;
import jakarta.annotation.Resource;
import lombok.Data;
import org.springframework.stereotype.Component;
@Data
@Component
public class Teacher {
@Resource
private Student stu;
}
@Resource特性:
1、默认按照属性名称byName方式去找。如果byName找不到按照byType。逻辑或关系。
2、如果只指定type属性,优先按照byType去找,如果找到多个,按照属性名byName去找。逻辑或关系。
3、如果只指定name属性,则固定按照name属性值去byName找。此时和属性名无关。
4、如果type和name都指定,则都生效。先byType确定范围,再byName从里面找符合条件的。都配 置时是一种逻辑与的关系。