目录
注解开发前的准备
@Component、@Scope、@PostConstruct、@PreDestroy注解
@Value注解
?@Autowired
@Qualifier
@Primary
@Resource
全注解开发
依赖加载
注解开发前的准备
要想使用注解进行开发,必须要启动注解扫描,加载类配置中的注解项
<context:component-scan base-package="packageName"></context:component-scan>
说明:
- 在进行包所扫描时,会对配置的包及其子包中所有文件进行扫描
- 扫描过程是以文件夹递归迭代的形式进行的
- 扫描过程仅读取合法的java文件
- 扫描时仅读取spring可识别的注解
- 扫描结束后会将可识别的有效注解转化为spring对应的资源加入IoC容器
注意:
- 无论是注解格式还是XML配置格式,最终都是将资源加载到IoC容器中,差别仅仅是数据读取方式不同
- 从加载效率上来说注解优于XML配置文件
@Component、@Scope、@PostConstruct、@PreDestroy注解
先通过一个类介绍@Component、@Scope、@PostConstruct、@PreDestroy注解的使用????????
package com.jjs.dao;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
@Component(value = "useDao")//声明这个类有spring管理,加入spring容器
@Scope(value = "singleton")//指定单例或者非单例
public class UserDaoImpl implements UserDao {
public void save() {
System.out.println("已保存");
}
@PostConstruct //初始化方法
public void init(){
System.out.println("初始化完成");
}
@PreDestroy //销毁方法
public void destroy (){
System.out.println("销毁");
}
}
@Component与@Controller、@Dao、@Service的功能其实完全相同,只是spring用在不同场景给的一个名称区别,用于表示是干啥用的,并且后续可能会针对性的实现某些功能,但是现在还没有实现
@Value注解
说明:
-
value值仅支持非引用类型数据,赋值时对方法的所有参数全部赋值 -
value值支持读取properties文件中的属性值,通过类属性将properties中数据传入类中 -
value值支持SpEL -
@value注解可以定义在方法上或者属性上,如果添加在属性上方,可以省略set方法(set方法的目的是为属性赋值)
使用案例:
准备阶段:
先在resources目录下创建一个application.properties文件 里面写入两条数据
username=zangsan
password=3.14159265
然后通过注解载入配置文件@PropertySource("classpath:application.properties")
最后通过@Value配个el表达式获取值
package com.jjs.dao;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
@Component(value = "userDao")
@PropertySource("classpath:application.properties") //加载properties配置文件
public class UserDaoImpl implements UserDao {
@Value("${username}")
private String username;
@Value("${password}")
private String password;
public void save() {
System.out.println("username:"+username);
System.out.println("password:"+password);
}
}
?@Autowired
说明:通过Autowired可以实现引用类型的注入,注入是先通过类型进行匹配,如果有同样类型存在的话,就会根据id进行匹配,下面通过代码进行解释
首先是一个接口userDao
package com.jjs.dao;
public interface UserDao {
void save();
}
创建一个UserDao实现类UserDaoImpl1
package com.jjs.dao;
import org.springframework.stereotype.Component;
@Component(value = "userDao1")
public class UserDaoImpl implements UserDao {
public void save() {
System.out.println("userDao1起作用");
}
}
这时候将UserDao注入UserService中
package com.jjs.service;
import com.jjs.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class UserServiceImpl implements UserService {
@Autowired
private UserDao useDao;
public void save() {
useDao1.save();
}
}
结果:
这个时候就会根据UserDao这个类型识别到这个类,因为有唯一的实现类,所以成功注入
这个时候再创建一个UserDao实现类UserDaoImpl2
package com.jjs.dao;
import org.springframework.stereotype.Component;
@Component(value = "userDao2")
public class UserDaoImpl2 implements UserDao {
public void save() {
System.out.println("userDao2起作用");
}
}
这时候再运行一次就会报以下错误,意思是根据类型查找,有重复的两个实现类都实现了UserDao接口,这时候根据bean的ID进行匹配,但是没有找到匹配的ID,由此已经可以看出,它是先根据类型进行匹配,当类型匹配冲突的时候,就进行ID匹配。
根据ID匹配是以bean的ID和声明注入类型的变量进行匹配。
?
?
?这个时候修改以下变量名字与其中一个ID相同就可以匹配上了
package com.jjs.service;
import com.jjs.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao1;
public void save() {
useDao.save();
}
}
@Qualifier
继续上面的例子,如果说变量名就想取为userDao,或者换个说法,当类型相同,变量名还相同的时候就可以@Qualifier这个注解进行区分,在@Qualifier表名bean的id
package com.jjs.service;
import com.jjs.dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
@Component
public class UserServiceImpl implements UserService {
@Autowired
@Qualifier("userDao1")
private UserDao userDao;
public void save() {
userDao.save();
}
}
@Primary
继续上面的例子,在正常的企业开发中,很少会对一个接口做出两套实现类,所以在大多数的情况下,基本上都不会@Component或者@Service、@Dao中加上id名字。但是如果有的时候某个同事突然给了第二套实现方案,这时候可以使用Primary来标明优先级。就指定每次加载的时候都加载被@Primary注解标记的类
package com.jjs.dao;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
@Component
@Primary
public class UserDaoImpl implements UserDao {
public void save() {
System.out.println("userDao1起作用");
}
}
@Resource
@Resource是@Autowired和@Quelifier的组合,通过name设置注入的bean的id
package com.jjs.service;
import com.jjs.dao.UserDao;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@Component
public class UserServiceImpl implements UserService {
@Resource(name = "userDao")
private UserDao userDao;
public void save() {
userDao.save();
}
}
全注解开发
既然说是全注解开发,那么就是要想办法替换掉spring的配置文件
这时候就要引入一个配置类,用来代替spring的配置文件
package com.jjs.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan("com")
public class SpringConfig {
}
上述代码中,@Configuration就可以替代Spring的配置文件,而@ComponentScan则代替包扫描
接下来就是要加载配置类
import com.jjs.config.SpringConfig;
import com.jjs.service.UserServiceImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class UserAPP {
public static void main(String[] args) {
// 加载配置文件
ApplicationContext applicationContext =
new AnnotationConfigApplicationContext(SpringConfig.class);
// 获取资源
UserServiceImpl userDao = (UserServiceImpl) applicationContext.getBean("userServiceImpl");
userDao.save();
}
}
依赖加载
@DependsOn
范例:
@DependsOn("beanId")
public class ClassName {
}
@Order
- 名称:@Order
- 类型:配置类注解
- 位置:配置类定义的位置(类上)
- 作用:控制配置类的加载顺序
范例:
@Order(1) //数字越小优先级越高
public class SpringConfigClassName {
}
|