注解编程
注解编程:指的是在类或者方法上加入特定的注解(@XXX)来完成特定功能的开发。
为什么要注解编程?
- 注解开发方便,代码简洁,开发速度大大提高
- Spring的开发潮流(从2.x版本引入注解,3.x版本完善,到SpringBoot普及)
环境准备
首先要在maven的pom包中引入Spring的相关jar包(这个不用说),然后再applicationContext.xml中加入
<context:component-scan base-package="com.prince" />
这个标签的作用是开启注解编程,并告诉Spring需要搜索的包。
基础注解
对象创建相关注解
@Component
作用:替换掉原有Spring配置文件中的bean标签
用法:直接在类前面加上该注解
@Component
public class User {
其中
- id属性,默认值是类名首字母小写(如User -> user,UserDao -> userDao),可以通过value属性来指定
- class属性:通过反射获取
测试:
@Test
public void test(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicaationContext.xml");
User user = applicationContext.getBean("user", User.class);
System.out.println("user = " + user);
}
衍生注解:(效果完全一样,只是名字不同而已,功能没有区别)
@Repository
@Service
@Controller
@Scope
作用:控制简单对象的创建次数(等同于原来bean标签的scope属性)
<bean id="" class="" scope="singleton|prototype"></bean>
用法:直接在类前面加上注解
@Component
@Scope("singleton")
public class User {
注意:默认值singleton
@Lazy
作用:延迟创建单实例对象(替换掉原来bean标签的lazy属性)
<bean id="" class="" lazy="false"></bean>
用法:在类前面加上该注解,代表延迟加载,只在获取该对象的时候才会创建。
@Component
@Lazy
public class User {
与生命周期相关的注解
使用到两个注解:
- 初始化相关方法:
@PostConstruct
- 销毁方法:
@PreDestroy
用法:直接在类的对应方法前面加上该注解即可
(注意导入javax的包,这两个注解是java提供的而不是spring)
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
@Component
public class Product {
@PostConstruct
public void myInit(){
System.out.println("Product.myInit");
}
@PreDestroy
public void myDestroy(){
System.out.println("Product.myDestroy");
}
}
测试:
@Test
public void test2(){
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicaationContext.xml");//工厂创建,对象创建,调用初始化方法
applicationContext.close(); //工厂关闭,对象销毁,调用销毁方法
}
注意:这两个注解不是Spring提供的,而是JSR(JAVAEE规范)520,这再一次地验证,通过注解实现接口的契约型。
注入相关注解
@AutoWired
作用:把这个注解加在成员变量或者setter方法上,Spring就会自动根据 类型 进行注入。这个注解主要用于 用户自定义类型 的注入
比如在UserService里注入UserDao:
@Repository
public class UserDaoImpl implements UserDao {
@Override
public void insert() {
System.out.println("UserDaoImpl.insert");
}
}
@Service
public class UserService {
@Autowired
private UserDao userDao;
public UserService(UserDao userDao) {
this.userDao = userDao;
}
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
}
细节:
- 如果想根据id注入,而不是类型,可以和
@Qualifier
注解配合使用
@Autowired
@Qualifier("userDaoImpl")
private UserDao userDao;
- JavaEE规范JSR250中有类似功能的注解
@Resource(name = "")
,基于id值进行注入,等同于@Autowired
和@Qualifier
的结合
//import javax.annotation.Resource;
@Resource(name = "userDaoImpl")
private UserDao userDao;
当不指定name属性的时候,将会按照类型进行注入
- JavaEE规范的JSR330中还有一个注解
@Inject
,作用和@Autowired
完全一致,使用时需要导入依赖:
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
@Value
这个注解主要用于JDK内置类型的注入,使用方法:直接在成员变量前面加上注解。
@Component
public class User {
@Value("123456")
private Integer id;
@Value("abcabc")
private String username;
为了解耦合,可以把Value里的值都抽取到一个properties文件里,然后让Spring读取这个配置文件来进行注入(配置文件参数化)。
id = 123456
username = abcabc
在Spring 的applicationContext.xml中配置,读取properties文件
<context:property-placeholder location="classpath:/user.properties" />
然后@Value
注解中使用EL表达式:
@Component
public class User {
@Value("${id}")
private Integer id;
@Value("${username}")
private String username;
注意:
@Value
注解不能放在静态成员变量前面,如果放,也是注入失败。@Value
+Properties
的注入方式不支持集合类型,如果需要,需要用到Spring提供的新配置形式 YAML 和 YML- 可以使用
@PropertySource
注解来代替xml中的配置<context:property-placeholder location="classpath:/user.properties" />
@Component
@PropertySource("classpath:/user.properties")
public class User {
@Value("${id}")
private Integer id;
@Value("${username}")
private String username;
注解扫描
开启注解扫描:自动扫描指定包及其子包下的所有类。
<context:component-scan base-package="com.prince" />
排除方式
在context:component-scan
标签内部嵌套context:exclude-filter
标签即可!
<context:component-scan base-package="com.prince" >
<context:exclude-filter type="" expression=""/>
</context:component-scan>
type属性共有5中取值:
- aspectj
通过切入点表达式(类切入点 和 包切入点)进行排除。
<!-- 排除com.prince.service包及其子包下的所有类 -->
<context:exclude-filter type="aspectj" expression="com.prince.service..*"/>
<!-- 排除任意包下所有名为User的类 -->
<context:exclude-filter type="aspectj" expression="*..User"/>
注意:使用需要导入aspect的相关依赖
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
- annotation
排除使用指定注解的类
<!-- 排除使用@Service注解的类 -->
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/>
- assignable
排除指定类型
<!-- 排除User类 -->
<context:exclude-filter type="assignable" expression="com.prince.bean.User"/>
- regex:正则 custom:自定义
这两个使用得比较少
包含方式
和排除方式一样,这个嵌套的是context:include-filter
<context:component-scan base-package="com.prince" use-default-filters="false">
<context:include-filter type="" expression=""/>
</context:component-scan>
其中type和expression和排除方式是一模一样的。
主要是包含方式要指定use-default-filters="false"
,表示让Spring默认的注解扫描失效,只有指定了这个注解的值为false,Spring才会只扫描context:include-filter
中配置的类,否则Spring还是会对base-package
指定的包及其子包全部扫描进去。
高级注解
Spring在3.x中提供的注解,用于替换XML配置文件。
配置类
不再使用ApplicationContext.xml的配置文件,取而代之的是由@Configuration
标注的配置类。
@Configuration
public class AppConfig {
}
创建ApplicationContext类的时候,不再使用ClassPathApplicationContext,而是使用AnnotationConfigApplicationContext
//使用AppConfig这个配置类
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
//扫描com.prince.config包及其子包下所有的配置类
ApplicationContext applicationContext = new AnnotationConfigApplicationContext("com.prince.config");
@Configuration
注解的本质:也是@Component
的衍生注解:
日志
不推荐log4j,使用logback作为日志框架:
- 先引入logback相关依赖
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.30</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.30</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>org.logback-extensions</groupId>
<artifactId>logback-ext-spring</artifactId>
<version>0.1.5</version>
</dependency>
- 引入logback.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- 控制台输出 -->
<appender name="STDOUT"
class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<!--格式化输出: %d表示⽇期, %thread表示线程名,
%-5level:级别从左显示5个字符宽度%msg:⽇志消息, %n是换⾏符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
</encoder>
</appender>
<root level="DEBUG">
<appender-ref ref="STDOUT" />
</root>
</configuration>
@Bean注解的使用
@Bean
注解在配置bean中使用,等同于XML配置中的bean标签
把@Bean
注解加到一个方法中,返回值是要创建的对象的类型,方法名就是id值,再把对象创建的代码放到方法体中即可!
- 创建简单对象
@Bean
public User user(){
User user = new User();
user.setId(10086);
user.setUsername("prince");
return user;
}
- 创建复杂对象
@Bean
public Connection connection(){
try {
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql:///mydata","root","root");
return conn;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
- 使用FactoryBean创建复杂对象(不常用)
import org.springframework.beans.factory.FactoryBean;
import java.sql.Connection;
import java.sql.DriverManager;
public class ConnectFactoryBean implements FactoryBean<Connection> {
@Override
public Connection getObject() throws Exception {
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql:///mydata","root","root");
return conn;
}
@Override
public Class<?> getObjectType() {
return Connection.class;
}
@Override
public boolean isSingleton() {
return false;
}
}
在配置类中直接引用这个ConnectFactoryBean的getObject即可
@Bean
public Connection connection1(){
Connection connection = null;
try {
connection = new ConnectFactoryBean().getObject();
} catch (Exception e) {
e.printStackTrace();
}
return connection;
}
细节:
- 自定义id值,默认是取方法名作为默认的id值,也可以给Bean注解加上参数作为id值
@Bean("u") //创建一个对象,id值是u
public User user(){
- 控制对象创建次数
@Bean("u")
@Scope("prototype")
public User user(){
@Bean注解的注入
用户自定义类型
原来XML中的配置是这样的:
<bean id="userDao" class="com.prince.dao.UserDaoImpl" />
<bean id="userService" class="com.prince.service.UserServiceImpl">
<property name="userDao" ref="userDao" />
</bean>
换成注解之后是这样的:
- UserDao对象的创建:
@Bean
public UserDao userDao(){
return new UserDaoImpl();
}
- UserService的创建,由于需要依赖注入上面的UserDao,所以要先获取到我们创建的UserDao再通过setter注入,有两种方法:
- 直接把UserDao当成函数的参数传进去
@Bean
public UserService userService(UserDao userDao){
UserServiceImpl userService = new UserServiceImpl();
userService.setUserDao(userDao);
return userService;
}
- 第二种方法更为简单,不需要传参数,直接在调用setUserDao的时候把函数传进去
@Bean
public UserService userService(){
UserServiceImpl userService = new UserServiceImpl();
userService.setUserDao(userDao());
return userService;
}
JDK类型
@Bean
public User user(){
User user = new User();
user.setId(10086);
user.setUsername("prince");
return user;
}
细节:可以配合@PropertySource
和 @Value
注解,把要注入的值放到配置文件中,进行解耦合
@Configuration
@PropertySource("classpath:/user.properties")
public class AppConfig {
@Value("${id}")
private Integer id;
@Value("${name}")
private String username;
@Bean
public User user(){
User user = new User();
user.setId(id);
user.setUsername(username);
return user;
}
@ComponentScan
注解扫描注解
@Configuration
@ComponentScan(basePackages = "com.prince")
public class AppConfig1 {
排除策略:(和XML的类似)
@Configuration
@ComponentScan(basePackages = "com.prince",
excludeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = {UserService.class}),
@ComponentScan.Filter(type = FilterType.ASPECTJ, pattern = {"com.prince.dao..*"})
}
)
public class AppConfig2 {
}
包含策略:(和XML的一样,也要先useDefaultFilters = false
,取消默认的扫描策略)
@Configuration
@ComponentScan(basePackages = "com.prince",
useDefaultFilters = false,
includeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = {UserService.class}),
@ComponentScan.Filter(type = FilterType.ASPECTJ, pattern = {"com.prince.dao..*"})
}
)
public class AppConfig2 {
}
多配置创建对象的优先级
配置Bean创建对象的优先级:@Component注解创建的对象 < @Bean注解创建的对象 < XML中bean标签创建的对象
高优先级可以覆盖低优先级(覆盖的前提是对象的ID值保持一致!)
怎么同时使用配置类和配置文件?加入@ImportResource
注解。
@Configuration
@ImportResource("classpath:/applicationContext.xml")
public class AppConfig2 {
}
为了解决耦合问题,比如前面的UserDao
@Bean
public UserDao userDao(){
return new UserDaoImpl();
}
当以后如果需要更改UserDao的实现类,不再是UserDaoImpl,需要改成新的UserDaoImplNew的时候,就不需要修改源代码,直接用配置覆盖的方式,重新在XML中配置即可:
<bean id="userDao" class="com.prince.dao.UserDaoImplNew" />
这样子获取id为userDao的对象的时候,获取的是UserDaoImplNew而不是UserDaoImpl
多配置信息的整合
- 为什么会有多个配置信息?
拆分多个配置类的开发,是一种模块化开发的形式,也体现了面向对象各司其职的设计思想。 - 多配置信息整合的方式
- 多个配置类的整合
- 配置类和
@Component
相关注解的整合 - 配置类和XML配置文件的整合
- 整合多种配置需要关注的要点
- 如何使多配置的信息汇总成一个整体
- 如何实现跨配置的注入(一个配置类创建的对象中注入另一个配置类创建的对象)
多个配置类的整合
- 在创建ApplicationContext的时候扫描整个包下的所有配置类
//扫描com.prince.config包及其子包下所有的配置类
ApplicationContext applicationContext = new AnnotationConfigApplicationContext("com.prince.config");
- 再其中一个配置类中用
@Import
注解来引入另一个配置类
@Configuration
@Import(AppConfig2.class)
public class AppConfig1 {
然后再创建ApplicationContext的时候,只需要传入AppConfig1.class
就可以同时读取两个配置类的信息
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig1.class);
这样子等同于XML中的配置:
<import resource="classpath:applicationContext1.xml" />
- 在AnnotationConfigApplicationContext中指定多个配置类(可变参数)
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig1.class, AppConfig2.class);
跨配置类的对象注入:
@Configuration
@Import(AppConfig2.class)
public class AppConfig1 {
@Bean
public UserDao userDao(){
return new UserDaoImpl();
}
}
//===================================================
//AppConfig2中创建的UserService,需要注入AppConfig1中创建的UserDao,
//只需要在AppConfig2中创建一个成员变量,并加上@Autowired注解即可。
//===================================================
@Configuration
public class AppConfig2 {
@Autowired
private UserDao userDao;
@Bean
public UserService userService() {
UserServiceImpl userService = new UserServiceImpl();
userService.setUserDao(userDao);
return userService;
}
}
**在应⽤配置类的过程中,不管使⽤哪种⽅式进⾏配置信息的汇总,其操作⽅式都是通过成员变量加⼊@Autowired注解完成。 **
配置类和@Component相关注解的整合
使用@ComponentScan
注解来扫描所有@Component
创建的对象,注入的时候也是采用@Autowired
的方式
@Configuration
@ComponentScan("com.prince.dao")
public class AppConfig2 {
@Autowired
private UserDao userDao;
@Bean
public UserService userService() {
UserServiceImpl userService = new UserServiceImpl();
userService.setUserDao(userDao);
return userService;
}
}
@Component
public class UserDaoImpl implements UserDao{
配置类与配置文件的的整合
使用@ImportResource
来引入XML配置文件
@Configuration
@ImportResource("classpath:applicationContext.xml")
public class AppConfig2 {
@Autowired
private UserDao userDao;
@Bean
public UserService userService() {
UserServiceImpl userService = new UserServiceImpl();
userService.setUserDao(userDao);
return userService;
}
}
<bean id="userDao" class="com.prince.dao.UserDaoImpl" />
纯注解版AOP编程
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl {
public void register(){
System.out.println("UserServiceImpl.register");
}
}
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Aspect //切面类
@Component
public class MyAround {
@Around("execution(* com.prince.aop..*(..))")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("====================log=====================");
Object ret = joinPoint.proceed();
return ret;
}
}
@Configuration
@EnableAspectJAutoProxy //等同于<aop:aspectj-autoproxy />
@ComponentScan("com.prince.aop")
public class AopConfig {
}
细节分析:
- 代理创建模式的切换(JDK / Cglib)
原XML中是这样子设置的
<aop:config proxy-target-class="true">
</aop:config>
<!--或者-->
<aop:aspectj-autoproxy proxy-target-class="true" />
注解的方式:
@EnableAspectJAutoProxy(proxyTargetClass = true)
- SpringBoot中AOP的开发方式,只需要前两步(原始对象、切面类),不需要
@EnableAspectJAutoProxy
,已经默认设置好了。而且SpringAOP的默认代理实现是JDK,而SpringBoot AOP的默认实现是CGlib。
纯注解版Spring+Mybatis整合
整合
- druid连接池
XML 中的配置:
<bean class="com.alibaba.druid.pool.DruidDataSource" id="dataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mydata"/>
<property name="username" value="root" />
<property name="password" value="root" />
</bean>
配置类中的配置:
@Bean
public DataSource dataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/mydata");
dataSource.setUsername("root");
dataSource.setPassword("root");
return dataSource;
}
- SqlSessionFactoryBean
XML 中的配置:
<!--配置SqlSessionFactoryBean-->
<bean class="org.mybatis.spring.SqlSessionFactoryBean" id="factoryBean">
<!--指定DataSource数据库连接池-->
<property name="dataSource" ref="dataSource" />
<!--给实体类设置别名-->
<property name="typeAliasesPackage" value="com.prince.entity" />
<!--设置mapper.xml的文件路径-->
<property name="mapperLocations">
<list>
<value>mapper/*Mapper.xml</value>
</list>
</property>
</bean>
配置类中的配置:(注意需要注入上一步创建的DataSource对象)
@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource){
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource); //注入DataSource
sqlSessionFactoryBean.setTypeAliasesPackage("com.prince.mybatis");
sqlSessionFactoryBean.setMapperLocations(new ClassPathResource("mapper/UserDaoMapper.xml"));
return sqlSessionFactoryBean;
}
- MapperScannerConfigure
XML 中的配置:
<!--配置MapperScannerConfigurer-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer" id="configurer">
<!--SqlSessionFactoryBean-->
<property name="sqlSessionFactoryBeanName" value="factoryBean" />
<!--指定Dao接口所在的包-->
<property name="basePackage" value="com.prince.dao" />
</bean>
配置类中的配置:
这个我们不需要专门去创建一个MapperScannerConfigurer,Spring已经为我们提供了一个注解。直接把这个注解加到配置类上面就行了。
@Configuration
@ComponentScan("com.prince.mybatis")
@MapperScan(basePackages = {"com.prince.mybatis.dao"})
public class MybatisConfig {
@MapperScan
注解只需要指定一个basePackages,表示Dao接口存放的位置。不需要专门指定sqlSessionFactoryBeanName,因为把注解加到类上,Spring还是可以扫描到这个类里创建的SqlSessionFactoryBean,而且创建SqlSessionFactoryBean的时候id值是可以任意取的。
完整代码:
@Configuration
@ComponentScan("com.prince.mybatis")
@MapperScan(basePackages = {"com.prince.mybatis.dao"})
public class MybatisConfig {
@Bean
public DataSource dataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/mydata");
dataSource.setUsername("root");
dataSource.setPassword("root");
return dataSource;
}
@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource){
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource); //注入DataSource
sqlSessionFactoryBean.setTypeAliasesPackage("com.prince.mybatis");
sqlSessionFactoryBean.setMapperLocations(new ClassPathResource("mapper/UserDaoMapper.xml"));
return sqlSessionFactoryBean;
}
}
细节
- MapperLocations编码时通配的写法
在XML配置中,MapperLocations是可以直接写通配符的:
<property name="mapperLocations">
<list>
<value>mapper/*Mapper.xml</value>
</list>
</property>
而注解配置中,这样子配置是会报错的:
sqlSessionFactoryBean.setMapperLocations(new ClassPathResource("mapper/*Mapper.xml"));
解决办法:使用 ResourcePatternResolver ( PathMatchingResourcePatternResolver )
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource[] resources = resolver.getResources("mapper/*Mapper.xml");
sqlSessionFactoryBean.setMapperLocations(resources);
因为sqlSessionFactoryBean.setMapperLocations
的参数是Resource类型的可变参数,所以可以直接传入一个数组。
- 配置类中数据的耦合问题
解决:数据库的DriverClassName,URL,username,password可以抽取到一个properties配置文件中,然后再利用@PropertySource
和@Value
注解。
事务
原来的XML配置版本:
<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="dataSourceTransactionManager">
<!--传入dataSource数据库连接池-->
<property name="dataSource" ref="dataSource"/>
</bean>
<!--组装切面-->
<tx:annotation-driven transaction-manager="dataSourceTransactionManager" />
<bean class="com.prince.service.UserServiceImpl" id="userService">
<!--Spring与Mybatis整合的时候会创建一个UserDao,直接把这个UserDao注入即可-->
<property name="userDao" ref="userDao"/>
</bean>
注解配置版本:
- TransactionManager
@Bean
public DataSourceTransactionManager dataSourceTransactionManager(){
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
dataSourceTransactionManager.setDataSource(dataSource());
return dataSourceTransactionManager;
}
- tx:annotation-driven:
@EnableTransactionManagement(proxyTargetClass = true)
public class MybatisConfig {
(注解一样不需要手动输入TransactionManager的id值,因为注解加到类上,Spring可以扫描这个类的所有TransactionManager)
有一个bug,使用JDK动态代理的时候会报错,我也不知道是什么原因,用cglib没问题,所有我就加上了proxyTargetClass = true
- UserService:
@Service
@Transactional
public class UserServiceImpl implements UserService{
@Autowired
UserDao userDao;
@Override
public void insert(User user) {
userDao.insert(user);
}
@Override
public User login(String username, String password) {
return userDao.login(username,password);
}
}
(使用了@Service
和@Autowired
还完成对象创建)
YAML
YML(YAML)是⼀种新形式的配置⽂件,比XML更简单,比Properties更强大。
Properties配置问题:
- 表达过于繁琐,无法表达数据的内在联系。
- 无法表达对象、集合类型
语法
- 基本语法(key: value的格式,注意冒号后面需要留一个空格!)
name: prince
password: 123456
- 对象(注意缩进!)
person:
name: prince
password: 123456
- 集合(注意缩进!!每一个值以-开头,并留一个空格)
list:
- 111111
- 222222