文章目录
准备工作
持久层创建
在com/spring/dao包下创建IaccountDao接口
内容:
package com.spring.dao;
public interface IaccountDao {
public void saveUser();
}
在com/spring/dao/impl包下创建AccountDaoImpl类
package com.spring.dao.impl;
import com.spring.dao.IaccountDao;
import org.springframework.stereotype.Repository;
public class AccountDaoImpl implements IaccountDao {
public void saveUser() {
System.out.println("保存成功");
}
}
业务层创建
在com/spring/server包下创建IAccountserver接口
package com.spring.server;
public interface IAccountserver {
public void saveAccount();
}
在com/spring/server/impl包下创建Accountserverimpl类
package com.spring.server.impl;
public class Accountserverimpl implements IAccountserver {
private IaccountDao dao ;
public Accountserverimpl() {
System.out.println("accountserverimpl"+"被创建了");
}
@Override
public void saveAccount() {
dao.saveUser();
}
}
表示层创建
package com.spring;
import com.spring.server.IAccountserver;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args){
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
//根据id获取对象
IAccountserver accountserver=(IAccountserver)ac.getBean("acServer");
accountserver.saveAccount();
}
}
声明注解方式
方式1@ComponentScan注解
@ComponentScan(basePackages="com.test")
@ComponentScan(basePackages={"com.review"})
public class Main {
public static void main(String[] args) {
ApplicationContext ac = new AnnotationConfigApplicationContext(Main.class);
Person person = ac.getBean("person",Person.class);
System.out.println(person.getName());
}
}
方式2配置文件(可选)
改变bean.xml
<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
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.spring"/>
</beans>
注解:
注解大体可以分为四类
1.创建对象 ---- 对应xml中的bean标签
2.注入数据 ---- 对应xml中的property标签
3.改变作用范围(多例,单例 ,request ,session ,global—session) ---- 对应xml中的scope属性
4.和生命周期相关 ---- 对应xml中的init-method和destroy-method
创建对象的注解
Component:
属性:
value:用于指定类的id:当此属性是空的时,id为首字母改为小写的类名,
以下三个注解功能和Component相同 只是针对不同的层级提供了不同的名称,以便区分
Controller:一般用于表现层
Service:一般用于业务层
Repository:一般用于持久层
可以试一下对Accountserverimpl类做出以下修改
@Service(value = "acServer")
public class Accountserverimpl implements IAccountserver {
private IaccountDao dao ;
public Accountserverimpl() {
System.out.println("accountserverimpl"+"被创建了");
}
@Override
public void saveAccount() {
dao.saveUser();
}
}
主函数:
public static void main(String[] args) {
ApplicationContext ac = new AnnotationConfigApplicationContext(Main.class);
//根据id获取对象
IAccountserver accountserver=(IAccountserver)ac.getBean("acServer");
System.out.println(accountserver);
}
此时运行即可看到结果
同样给AccountDaoImpl添加注解 以便后面的使用
@Repository(value = "AD")
public class AccountDaoImpl implements IaccountDao {
@Override
public void saveUser() {
System.out.println("保存成功");
}
}
注入数据注解
Autowired:(此注解只能够自动注入)
作用:自动按照类型注入,只要容器中有一个bean对象和要注入的类型匹配就可以注入
若ioc容器中没有任何一个类型与其匹配则注入失败
若ioc容器中有多个匹配项则先根据需要注入变量的数据名称来注入
出现位置:成员变量或方法上
Qualifier
作用:按照类型注入的基础上再按照名称注入 在给类成员注入时不能单独使用,但在方法传参时可以单独使用
属性:
value:用于指定注入bean的id
这时我们更改以下主类让其调用save方法
Resource
作用:按照类型注入的基础上再按照id注入,可以单独使用
属性:name:传入id
《--------------------------以上三个标签都只能注入bean数据类型而不能注入基本数据类型和string---------------------------------》
value
作用:基本数据类型和string的注入
属性:
value:用于指定数据的值 可以使用spel
spel的写法:${表达式}
演示:
public static void main(String[] args){
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
//根据id获取对象
IAccountserver accountserver=(IAccountserver)ac.getBean("acServer");
System.out.println(accountserver);
accountserver.saveAccount();
}
此时运行会发现出现了空指针异常
原因很明显Accountserverimpl中的dao没有初始化
那么我们就要对dao进行注入
这里使用@Autowired注解
Service(value = "acServer")
public class Accountserverimpl implements IAccountserver {
@Autowired
private IaccountDao dao ;
public Accountserverimpl() {
System.out.println("accountserverimpl"+"被创建了");
}
@Override
public void saveAccount() {
dao.saveUser();
}
}
此时便可以成功运行
由此可知@Autowired是通过数据类型在ioc容器中查找对应数据类型来注入的
但是又出现了新的问题,如果同时存在两个IaccountDao 的实现类,那spring会注入哪个呢
可以试一下:
我们复制一份AccountDaoImpl,取名AccountDaoImpl2
更改@Repository(value = "AD")
为 @Repository(value = "AD2")
此时再次运行主程序便会报错
这是因为同时有两个bean拥有相同数据类型时,spring不知道你想要的具体是哪个对象,我们有两种方式进行修改:
- 修改类中的变量名称使其与ioc容器中的id相同(显然不是什么好方法)
- 使用@Qualifier注解
@Qualifier注解在给类成员变量进行注入时需要与@Autowired配合使用
如:
@Service(value = "acServer")
public class Accountserverimpl implements IAccountserver {
@Autowired
@Qualifier("AD2")
private IaccountDao dao ;
public Accountserverimpl() {
System.out.println("accountserverimpl"+"被创建了");
}
@Override
public void saveAccount() {
dao.saveUser();
}
}
此时便可以正常运行,并获取到你想要的bean
但用两个注解是不是繁琐了一点
这里便有了Resource注解
我们使用@Resource(name = "AD")
和@Resource(name = "AD2")
注解来实现功能
即:
public class Accountserverimpl implements IAccountserver {
@Resource(name = "AD2")
private IaccountDao dao ;
public Accountserverimpl() {
System.out.println("accountserverimpl"+"被创建了");
}
@Override
public void saveAccount() {
dao.saveUser();
System.out.println(s);
}
}
!!----------------------注意以上三个注解只能注入bean对象而不能注入基本数据类型和String--------------------------!!
这时我们在Accountserverimpl中添加一个私有string类型的变量
我们可以通过value注解进行注入
@Service(value = "acServer")
@Scope(value = "prototype")
public class Accountserverimpl implements IAccountserver {
@Resource(name = "AD2")
private IaccountDao dao ;
@Value(value = "hello")
private String s;
public Accountserverimpl() {
System.out.println("accountserverimpl"+"被创建了");
}
@Override
public void saveAccount() {
dao.saveUser();
System.out.println(s);
}
}
此时调用saveAccount即可看见
改变作用范围
(singleton,prototype ,request ,session ,global—session) ---- 对应xml中的scope属性
Scope 与创建对象标签一起使用
作用:与xml中的scope属性一致
属性:value 传入singleton,prototype ,request ,session ,global—session
@Service(value = "acServer")
@Scope(value = "prototype")
public class Accountserverimpl implements IAccountserver {
@Resource(name = "AD2")
private IaccountDao dao ;
@Value(value = "hello")
private String s;
public Accountserverimpl() {
System.out.println("accountserverimpl"+"被创建了");
}
@Override
public void saveAccount() {
dao.saveUser();
System.out.println(s);
}
}
此时更改主程序
public class Test {
public static void main(String[] args){
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
//根据id获取对象
IAccountserver accountserver=(IAccountserver)ac.getBean("acServer");
IAccountserver accountserver2=(IAccountserver)ac.getBean("acServer");
System.out.println(accountserver==accountserver2);
// accountserver.saveAccount();
}
}
即可看见运行结果,已经成功的变为多例
生命周期注解
@PostConstruct 指定初始化函数
@PreDestroy指定销毁函数
@Service(value = "acServer")
public class Accountserverimpl implements IAccountserver {
@Resource(name = "AD2")
private IaccountDao dao ;
@Value(value = "hello")
private String s;
public Accountserverimpl() {
System.out.println("accountserverimpl"+"被创建了");
}
@Override
public void saveAccount() {
dao.saveUser();
System.out.println(s);
}
@PostConstruct
public void init(){
System.out.println("初始化");
}
@PreDestroy
public void end(){
System.out.println("对象销毁");
}
}
配置文件注解:
在前面的这些注解中能够大部分的去除对xml的依赖,但仍无法脱离xml
比如创建jar包中类的bean就不太可能,所以我们有了下面这些注解
Configuration和ComponentScar
Configuration
作用:指定当前类是一个配置类
ComponentScar
作用:用于通过注解指定spring在创建容器时要扫描的包
属性
value:它和basePackages的作用是一样的,都是用于指定创建容器时要扫描的包。
我们使用此注解就等同于在xmL中配置了:<context: component-scan base-package=“com.itheima”></context: component-scan>
@Configuration
@ComponentScan("com.spring")
public class SpringConfig {
}
这样就可以声明一个配置类了
bean
Bean
作用:用于把当前方法的返回值作为bean对象存入spring的ioc器中
属性:
name:用于指定bean的id,当不写时,默认值是当前方法的名称
当我们使用注解配置方法时,如果方法有参数, spring框架会去容器中查找有没有可用的bean对象。查找的方式和Autoviredi解的作用是一样的 当我们要指定容器中bean的id时,使@Qualifier注解
@Configuration
@ComponentScan("com.spring")
public class SpringConfig {
@Bean
@Scope("prototype")
public QueryRunner createQueryRunner(@Qualifier("ds1") DataSource dataSource){
return new QueryRunner(dataSource);
}
@Bean(name="ds1")
public DataSource createDataSource(){
try {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/spring_test");
dataSource.setDriverClass("com.mysql.cj.jdbc.Driver");
dataSource.setUser("root");
dataSource.setPassword("adminadmin");
return dataSource;
}
catch (Exception e){
throw new RuntimeException(e);
}
}
}
可以看见Bean注解是可以和Scope配合使用的
import
import
作用:导入其他配置类
属性:
Class<?>[] value() 传入一个或多个类的句柄(.class)有impact注解的为主配置,而其他为子配置类
PropertySource
PropertySource
作用:读取properties配置文件
属性:
value:指定文件名称和路径。
关键字:classpath 表示在类路径下
示例:
由于前面获取参数的方式过于粗暴
我们就可以使用PropertySource来获取参数
首先创建jdbcconfig.properties
jdbc.url=jdbc:mysql://localhost:3306/spring_test
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.user=root
jdbc.password=adminadmin
然后在SpringConfig文件里做修改
@Configuration
@ComponentScan("com.spring")
@PropertySource("classpath:jdbcconfig.properties")
public class SpringConfig {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.user}")
private String user;
@Value("${jdbc.password}")
private String password;
@Value("${jdbc.url}")
private String url;
@Bean
@Scope("prototype")
public QueryRunner createQueryRunner(DataSource dataSource){
return new QueryRunner(dataSource);
}
@Bean
public DataSource createDataSource(){
try {
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setJdbcUrl(url);
dataSource.setDriverClass(driver);
dataSource.setUser(user);
dataSource.setPassword(password);
return dataSource;
}
catch (Exception e){
throw new RuntimeException(e);
}
}
}
此时注解就调用成功了
在junit中调试时
在测试类中,如果需要使用spring直接写注解是无法使用的,我们首先需要导入依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.3.10</version>
</dependency>
在测试类加入
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class DbutilTest {
@Autowired
private IAccountService service;
@Test
public void testFindAll() {
。
。
。
。
}
此时在测试类中才能正常使用spring
总结
我们在注解配置时,并没有说所有情况变得更加方便,反而在对jar包配置时更加繁琐,所以在实际开发中,我们通常采用xml和注解相结合的方式来进行的,哪个方便就用哪个。