Spring注解开发:
Spring想要注入bean容器中,可以通过配置文件的方式,但是也可以通过注解的方式
在原本的xml配置文件中,有一个包扫描的配置,以递归的方式扫描该路径下的所有Spring可以识别的注解的文件
<context:component-scan base-package="packageName"/>
而在Java中想要省略这个也可以写一个配置类来替代这个配置文件,有一个注解可以写在这个配置文件类的上边,@ComponentScan("packageName"),不管是注解还是配置文件最后都是将资源添加到IOC容器中,注解的效率快于XML配置文件
注解开发步骤:
注解是基于源码的,所以如果想要将第三方的框架交给Spring工厂管理,那么就需要将源码给加上注解,这是不合适的,后边会说真没处理
首先创建一个class文件假设命名为BeanConfig.class 用来替代xml配置文件,这个BeanConfig首先添加一个注解@Configuration它是用来声明这是一个核心配置文件,然后再给他添加一个包扫描注解@ComponentScan("扫描的路径")用来扫描该包下所有文件的注解先当与下xml的<context:component-scan base-package="packageName"/>
他还有一个加载配置文件的注解@PropertySource("*.properties")然后可以使用注解@Value("${文件的key}") 这个value注解支持EL表达式,示例代码:
@Configuration //设置为核心配置文件
@PropertySource("db.properties") //加载properties文件
@ComponentScan("com.itheima") //扫描com.itheima包下的所有文件
public class BeanConfig {
@Bean("druidDataSource")
public DataSource createDruidDataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("${db.url}");
dataSource.setUsername("${db.username}");
dataSource.setPassword("${db.password}");
return dataSource;
}
}
然后这是核心配置文件,那么他是怎么可以像xml文件一样控制反转呢,可以通过注解来实现
@Component可以实现自动加入bean,
public interface IUserService {
public void saveUser(User user);
}
//实现类
@Component("userService")
public class UserServiceImpl implements IUserService {
@Override
public void saveUser(User user) {
System.out.println("UserSerive => saveUser方法");
}
}
这样就可以实现了,如果注解上边没有写value,那么就是默认的是该类的首字母小写的名字,例如上边的代码,如果只写了@Component没有值,那么他在xml中就相当于是<baen id="userServiceImpl" class="UserServiceImpl的路径" />
其实注解@Component也有衍生的注解@Controller、@Service 、@Repository三个注解。功能同等于@Component,不过这三个用的地方也有规定,一般在
表现层用@Controller,
在业务层用@Servie,
在持久层用@Repository
那么注入了以后之前在xml文件都是根据ClassPathXmlApplicationContext上下文来用里面的bean方法得到他的实例化对象,现在的话想要调用bean的实例化,那么就可以使用自动注入的方法去实现,通过注解@Autowired来实现注入这个实例化:例子:
@Service("userService")
public class UserServiceImpl implements UserService {
/*
@Autowired这个注解是自动注入,匹配他的bean,而注入以后的userDao的对象是他的实现类,例如userDao = com.itheima.dao.impl.UserDaoImpl@36f0f1be
@Qualifier是指定给userDao变量注入对象bean的id,如果就一个@Qualifier没写值,默认是使用成员变量名为id也就是userDao,
如果只写了@Qualifier,没有给定让他调用的id,那么bean就要有这个以变量名为名字的id,比如:
@Autowired
@Qualifier
private UserDao userDao;
@Qualifier是没有值的,而变量名又是userDao,那么这时候就必须有一个bean的id为userDao,如果没有他就会报错:
No qualifying bean of type 'com.itheima.dao.UserDao' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true), @org.springframework.beans.factory.annotation.Qualifier(value=)}
这是因为这个注解默认是调用变量名为id的bean,然而又没有这个id为这个变量名的bean,所以就会报错
如果加了@Qualifier又有多个实现类实现了注解下的接口,不过有没有id为变量名的那么都要指定他的id,不然报错
如果不加这个注解只有 @Autowired 而又有多个实现了注解下的接口,那么就默认是用id为注解下变量名的id,如果没有那么还是报错
*/
@Autowired
private UserDao userDao;
@Autowired
private DataSource dataSource;
public void save(User user) {
System.out.println("UserServiceImpl => save => 用户对象:" + user);
userDao.save(user);
System.out.println("======================");
try {
System.out.println(dataSource.getConnection().isClosed());
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
这个@Autowried是根据注入引用类型对象来注入,当容器中只有一个类型匹配那么可以不指定注入直接根据注解下边的类型来注入,如果有多个的话那么就要用指定注解 @Qualifier来指定,如果这个注解没有值那么就是根据下边的变量名为id去查
使用@Value来是注入数据,这个注解只能注入非引用类型的数据,代码例子:
public class ClassName{
@Value("100")
private int num;
@Value("黑马")
private String name;
}
@Value这个注解也能支持EL表达式,也能支持读取properties文件的值,可以省略setter方法,但是想要使用这个注解去读取properties文件,那么就要先使用@PropertiesSource("*.properties");然后通过el表达式去读取他的值
使用AnnotationConfigApplicationContext类代替ClassPathXmlApplicationContext类来获取他的实例化对象,之前的是写xml文件,现在这个是用配置类名.class,
使用IOC的注解配置-加载第三方资源:
想要将第三方资源交给Spring容器,那么就需要修改源码添加注解,这时候就可以使用另外一个注解@Bean,例如在xml文件中注入DruidDataSource,那么代码如下:
<?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
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 配置Druid中的类,作为Spring容器中的一个资源 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/db1"></property>
<property name="username" value="root"></property>
<property name="password" value="itheima"></property>
</bean>
</beans>
然后通过bean的id标签去Spring工厂获得他的实例,这样就引入了,但是现在学的是注解开发,接下来的代码时注解开发代码:
public class ClassName{
@Bean("名字")
public 返回值类型 方法名(){
return 返回值;
}
}
使用注解引入第三方框架:
@Component //@Bean所在的类必须被spring扫描加载,否则该注解无法生效
public class MyDataSource {
@Bean("druidDataSource") //bean的id名(spring容器中资源的名字)
public DataSource createDruidDataSource(){
//创建第三方资源对象
DruidDataSource druidDataSource = new DruidDataSource();
//设置参数
druidDataSource.setDriverClassName("com.mysql.jdbc.Driver");
druidDataSource.setUrl("jdbc:mysql://127.0.0.1:3306/db1");
druidDataSource.setUsername("root");
druidDataSource.setPassword("itheima");
//返回对象
return druidDataSource;
}
}
然后如果想要使用这个DataSource的时候可以通过自动注入来实现
@Autowried
private DataSource dataSource;
除了这个方式还有一个注解也可以实现:@Import("类名.class"),这个注解只能使用一次在同一个类中,如果想要添加多个给这个类中,那么可以@Import("{类名.class,类名1.class,类名2.class}")这样的数组来实现,这个导入的优先顺序时从左到右执行,而且是是在这个注解所在类中的diamagnetic执行完了然后再去执行这个注解导入的代码
使用@Import代码:
@Configurable //当前类是Spring配置类
@ComponentScan("com.itheima")//指定扫描的包
@PropertySource(value = "data.properties")//加载外部资源文件
@Import(MyDataSource.class) //导入MyDataSource类
public class SpringConfig {
}
//@Component //可以删除 (在配置类中导入了MyDataSource类)
public class MyDataSource {
@Bean("druidDataSource") //bean的id名(spring容器中资源的名字)
public DataSource createDruidDataSource(){
//创建第三方资源对象
DruidDataSource druidDataSource = new DruidDataSource();
//设置参数
druidDataSource.setDriverClassName("com.mysql.jdbc.Driver");
druidDataSource.setUrl("jdbc:mysql://127.0.0.1:3306/db1");
druidDataSource.setUsername("root");
druidDataSource.setPassword("itheima");
//返回对象
return druidDataSource;
}
}
第三种方式是直接在配置类中写:
@Configurable //当前类是Spring配置类
@ComponentScan("com.itheima")//指定扫描的包
@PropertySource(value = "data.properties")//加载外部资源文件
public class SpringConfig {
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.driver}")
private String driver;
@Bean
public DataSource creatDataSource() {
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setPassword(password);
druidDataSource.setUsername(username);
druidDataSource.setUrl(url);
druidDataSource.setDriverClassName(driver);
return druidDataSource;
}
}
这个也可以在使用类的时候使用scope来设置作用域也就是懒汉还是饿汉@Scope("prototype")或者@Scope("singleton")
注解也可以设置方法为初始化方法和销毁方法:
@Component
public class ClassName{
@PostConstruct
public void init() {
//初始化方法
}
}
@Component
public class ClassName{
@PreDestroy
public void destory() {
//销毁方法
}
}
Spring整合Mybatis(重点):
配置mybatisConfig来替代xml形式
package com.itheima.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
import javax.sql.DataSource;
@PropertySource("classpath:jdbc.properties")
public class MybatisConfig {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
//相当于替代了xml中的datasource的配置数据库
@Bean
public DataSource getDataSource() {
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setDriverClassName(driver);
druidDataSource.setUrl(url);
druidDataSource.setUsername(username);
druidDataSource.setPassword(password);
return druidDataSource;
}
/*SqlSessionFactoryBean是由mybatis提供的
底层会提供SqlSessionFactory
当开发者需要在service注入dao层的时候,提供的这个SqlSessionFactory会自动注入进去
但是需要dao层的扫描被制成bean,加一个注解@Repository
*/
@Bean
public SqlSessionFactoryBean getSqlSessionFactoryBean(DataSource druidDataSource) {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
/*pojo包扫描,相当于xml文件中的
<typeAliases>
<package name="com.itheima.domain"/>
</typeAliases>
*/
sqlSessionFactoryBean.setTypeAliasesPackage("com.itheima.domain");
//设置连接池,相当于xml中配置的连接池
sqlSessionFactoryBean.setDataSource(druidDataSource);
return sqlSessionFactoryBean;
}
//设置映射文件包扫描
/*
相当于xml文件中的
<mappers>
<package name="com.itheima.dao"></package>
</mappers>
*/
@Bean
public MapperScannerConfigurer getMapper() {
MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
mapperScannerConfigurer.setBasePackage("com.itheima.dao");
return mapperScannerConfigurer;
}
}
设置SpringConfig类引入mybtis的配置类
@Configuration
@ComponentScan("com.itheima")
@Import(MybatisConfig.class)
public class SpringConfig {
}