Spring学习笔记目录
使用配置数据源的项目继续练习
目录
Spring注解开发
注解 | 说明 |
---|---|
@Configuration | 使用在类上用于实例化Bean |
@Controller | 使用在web层类上用于实例化Bean |
@Service | 使用在service层类上用于实例化Bean |
@Repository | 使用在dao层类上用于实例化Bean |
@Autowired | 使用在字段上用于根据类型依赖注入 |
@Qualifier | 结合@Autowired一起使用用于根据名称进行依赖注入 |
@Resource | 相当于@Autowired+@Qualifier,按照名称进行注入 |
@Value | 注入普通属性 |
@Scope | 标注Bean的作用范围 |
@PostConstruct | 使用在方法上标注该方法是Bean的初始化方法 |
@PreDestroy | 使用在方法上标注该方法是Bean的销毁方法 |
XML配置方式(回顾)
回顾XML配置方式然后与注解开发进行比较,易于理解
项目结构:
新建接口UserDao.java:
package com.stu.dao;
/**
* @version:
* @author: 零乘一
* @description:
* @date: 2021/9/27 16:35
**/
public interface UserDao {
public void save();
}
新建实现类UserDaoImpl.java:
package com.stu.dao.impl;
import com.stu.dao.UserDao;
/**
* @version:
* @author: 零乘一
* @description:
* @date: 2021/9/27 16:37
**/
public class UserDaoImpl implements UserDao {
@Override
public void save() {
System.out.println("save runing....");
}
}
新建接口UserService.java:
package com.stu.service.dao;
/**
* @version:
* @author: 零乘亿
* @description:
* @date: 2021/9/27 16:39
**/
public interface UserService {
public void save();
}
新建实现类UserServiceImpl.java:
package com.stu.service.dao.impl;
import com.stu.dao.UserDao;
import com.stu.service.dao.UserService;
/**
* @version:
* @author: 零乘亿
* @description:
* @date: 2021/9/27 16:39
**/
public class UserServiceImpl implements UserService {
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void save() {
userDao.save();
}
}
新建类UserController.java:用于测试
package com.stu.web;
import com.stu.service.dao.UserService;
import com.stu.service.dao.impl.UserServiceImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @version:
* @author: 零乘亿
* @description:
* @date: 2021/9/27 16:51
**/
public class UserController {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = applicationContext.getBean(UserServiceImpl.class);
userService.save();
}
}
applicationContext.xml新增以下配置:
<bean id="userDao" class="com.stu.dao.impl.UserDaoImpl"/>
<bean id="userService" class="com.stu.service.dao.impl.UserServiceImpl">
<property name="userDao" ref="userDao"/>
</bean>
运行结果
运行UserController类文件
测试类中的save方法被成功执行,说明配置成功。
注解开发示例
查看applicationContext.xml文件中的配置
在使用注解代码开发时,会将以上的bean以注解的方式在代码中进行配置。
UserDaoImpl.java新增以下配置:
//<bean id="userDao" class="com.stu.dao.impl.UserDaoImpl"/>
@Component("userDao")
//<bean id="userService" class="com.stu.service.dao.impl.UserServiceImpl" />
@Component("userService")
//<property name="userDao" ref="userDao"></property>
@Autowired
@Qualifier("userDao")
做完以上配置后,运行UserController.java文件后发现控制台报错如下:
这是因为我们虽然在代码中配置了注解,但是在xml中并没有告诉spring我们配置了这些注解,所以要在xml配置组件扫描代码。
applicationContext.xml文件中新增以下代码块:
<!--组件扫描-->
<context:component-scan base-package="com.stu"/>
运行UserController.java文件
运行结果
成功打印出结果,说明注解配置成功。
分层注解
在上面的部分我们能够看到有很多的注解都可以用于bean的实例化,但是在上一个例子中只使用了@Component注解,其它的注解是为了更强的语义化。
在UserDaolImpl.java新增以下代码:
@Repository("userDao")
Dao层一般是用于数据持久层的,使用@Repository注解进行标注,这样语义化更好,在开发之后看代码时就能够很好的表示这一层是Dao。
UserServiceImpl.java新增以下代码:
@Service("userService")
这一层是Service所以将注解改成了@Service
运行UserController.java
运行结果
运行结果有打印结果,说明注解配置成功。
属性注入注解方式
①按照类型注入
@Autowired
②使用id的注入方式
@Autowired
@Qualifier("userDao")
使用②时要注意,在配置当中,相同类型的bean在Spring容器中只能存在一个,若存在多个则会不知道应该要注入哪个bean从而出错。
③相当于@Autowired+@Qualifier()的注入方式
@Resource(name="userDao")
jdk9以上不支持该操作,需要手动导入坐标。
注意:在使用注解进行属性注入时,在对象的内部不需要写对该属性的set方法,但是使用XML进行配置时就一定要协商。
在UserServiceImpl.java文件中的属性注入的注解中进行修改即可,修改之后在运行UserController查看打印结果。即可知道属性注入是否有成功。
普通属性注入
将UserServiceImpl.java定义的代码块进行替换:
public class UserServiceImpl implements UserService {
//<property name="userDao" ref="userDao"></property>
// @Autowired
// @Qualifier("userDao")
@Resource(name="userDao")
private UserDao userDao;
@Value("张三")
private String name;
@Override
public void save() {
System.out.println(name);
userDao.save();
}
}
运行结果
运行UserController.java文件:
成功打印出name说明配置成功,但这并不是注解value的主要用法。
普通属性注入使用EL表达式
将UserServiceImpl.java类重点的普通属性注入改为以下代码:
@Value("${jdbc.Driver}")
运行结果
运行UserController.java文件:
这才是注解Value的正确使用方法✔
代码解析
注解中的参数是一个EL表达式,表达式中的值是配置文件中的键值对中的其中一个key。
因为在xml中已经导入了properties文件中的键值对,所以在Spring空间中已经存在了这些键值对,所以在注解中写入EL表达式能够将通过key-value对的方式,通过key将value赋值给变量name。
新增初始化方法与销毁方法
UserController.java替换main方法
public static void main(String[] args) {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = applicationContext.getBean(UserServiceImpl.class);
userService.save();
applicationContext.close();
}
如果不执行close方法就无法看见destroy()方法的执行结果,因为在执行方法前,对象已经关闭。
UserServiceImpl.java新增以下代码:
//初始化执行
@PostConstruct
public void init(){
System.out.println("init....");
}
//对象销毁时执行
@PreDestroy
public void destroy(){
System.out.println("destroy....");
}
运行结果
Spring新注解
原始注解对于一些xml中的标签无法实现,所以需要引入新注解。
注解 | 说明 |
---|---|
@Configuration | 用于指定当前类是一个 Spring 配置类,当创建容器时会从该类上加载注解 |
@ComponentScan | 用于指定 Spring 在初始化容器时要扫描的包。 |
@Bean | 使用在方法上,标注将该方法的返回值存储到 Spring 容器中 |
@PropertySource | 用于加载.properties 文件中的配置 |
@Import | 用于导入其他配置类 |
新注解示例
目录结构:
新建SpringConfiguration.java:
package com.stu.config;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.*;
import javax.sql.DataSource;
import java.beans.PropertyVetoException;
/**
* @version:
* @author: 零乘一
* @description: Spring核心配置文件
* @date: 2021/9/28 15:30
**/
//标志该类是Spring的核心配置类
@Configuration
//<context:component-scan base-package="com.stu"/>
@ComponentScan("com.stu")
//<import resource="">
@Import({DataSourceConfiguration.class})
public class SpringConfiguration {
}
新建DataSourceConfiguration.java:
package com.stu.config;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.PropertySource;
import javax.sql.DataSource;
import java.beans.PropertyVetoException;
/**
* @version:
* @author: 零乘一
* @description: 数据源相关配置
* @date: 2021/9/28 15:44
**/
//<context:property-placeholder location="classpath:jdbc.properties" />
//<context:property-placeholder location="classpath:jdbc.properties" />
@PropertySource("classpath:jdbc.properties")//将properties中的数据载入Spring配置中
public class DataSourceConfiguration {
@Value("${jdbc.Driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String user;
@Value("${jdbc.password}")
private String password;
@Bean("dataSource") //Spring会将当前方法的返回值以指定名称存储到Spring容器中
public DataSource getDataSource() throws PropertyVetoException {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setDriverClass(driver);
dataSource.setJdbcUrl(url);
dataSource.setUser(driver);
dataSource.setPassword(driver);
return dataSource;
}
}
UserController.java新增以下代码:
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfiguration.class);
运行结果
成功打印,说明新注解配置成功。
可能遇见bug
①Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder ‘jdbc.driver’ in value “${jdbc.driver}”
以上bug说明jdbc.driver这个表示是无法被识别的,因此很有可能是配置文件中的k-v对值写错。获取的这方与文件中的key无法对应上。
新注解详解
①
②
在@Import({…})这个注解中,内容是一组数组,需要引入多个配置类时,在第一个配置类后再加上一个逗号",",然后再写上下一个配置类即可引入。
③
这样的路径引入的配置文件,文件需要放在resources文件夹才能够找到。
④
⑤AnnotationConfigApplicationContext类
这个类就是我们之前提到的加载类配置文件对于的Application实现类。