@Configuration用于定义配置类,替换掉xml配置文件
也就是说这个配置类就相当于配置文件
比如我创建一个Appconfig类指定为定义配置类就如下
@Configuration
public class Appconfig {
xxx
}
创建对象的工厂也有所不同
之前都是ClassPathXmlApplicationContext等等
现在变为了:AnnotationConfigApplicationContex
使用方法有两种:
? 反射
ApplicationContext context =new AnnotationConfigApplicationContext(Appconfig.class);
指定所在的包(Appconfig在AnnotationProgramming下面)
ApplicationContext context= new AnnotationConfigApplicationContext("org/AnnotationProgramming");
@Bean注解在配置bean中进?使?,等同于XML配置?件中的
也有点类似@Component注解
直接new出返回即可
@Bean
public User user(){
return new User();
}
在@Bean中直接完成
例如我要创建一个connetion对象
@Bean
public Connection connection() throws ClassNotFoundException, SQLException {
Class.forName("com.mysql.cj.jdbc.Driver");
Connection connection= DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc_test","root","123456");
return connection;
}
使用FactoryBean
声明一个ConnectionFactory类实现 FactoryBean接口
public class ConnectionFactory implements FactoryBean<Connection> {
@Override
public Connection getObject() throws Exception {
Class.forName("com.mysql.cj.jdbc.Driver");
Connection connection= DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc_test","root","123456");
return connection;
}
@Override
public Class<?> getObjectType() {
return Connection.class;
}
@Override
public boolean isSingleton() {
return false;
}
}
在配置Bean中如下实现
? 简单来说步骤如下:
@Bean
public Connection connectionFactoryConfig() {
ConnectionFactory connectionFactory=new ConnectionFactory();
Connection connection= null;
try {
connection = connectionFactory.getObject();
} catch (Exception e) {
e.printStackTrace();
}
return connection;
}
和之前的一样@Scope中的两个属性可以控制创建的时机
我们得把需要注入的类型给创建出来
比如我要注入UserDAO,那就得先创建出来
@Bean
public UserDAO userDAO(){
UserDAO userDAO=new UserDAOImpl();
return userDAO;
}
方式一:
? 直接声明为形式参数,前面必须先为其设置SET/GET方法
@Bean
public UserService service(UserDAO userDAO){
UserServiceImpl userService=new UserServiceImpl();
userService.setUserDAO(userDAO);
return userService;
}
方式二:
? 直接调用方法注入
@Bean
public UserService service1(){
UserServiceImpl userService=new UserServiceImpl();
userService.setUserDAO(userDAO());//userDAO()相当于返回的userDAO
return userService;
}
方式一:
? 直接手动设置,不过会有耦合问题
@Bean
public Customer customer(){
Customer customer= new Customer();
customer.setId("1");
customer.setName("SY");
return customer;
}
方式二:
? 通过配置文件设置,使用@PropertySource读取配置文件达到解耦
@PropertySource("classpath:/init.properties")
public class Appconfig {
@Value("${id}")
private String id;
@Value("${name}")
private String name;
@Bean
public Customer customer(){
Customer customer= new Customer();
customer.setId(id);
customer.setName(name);
return customer;
}
@ComponentScan注解在配置bean中进?使?,等同于XML配置?件中的context:component-scan标签
用于扫描相关注解
原理和之前一摸一样
1.如果要指定扫描的包则如下设置
@Configuration
@ComponentScan(basePackages = "org.AnnotationProgramming.Scan")
public class Appconfig_Scan {
}
2.也可以在工厂创建时指定
Spring源码:
public AnnotationConfigApplicationContext(String... basePackages) {
this();
scan(basePackages);
refresh();
}
1.basePackages 指定包
2.excludeFilters 排除方案
3.@ComponentScan.Filter 指定排除类型 有下面4种
4.value和pattern
@Configuration
@ComponentScan(basePackages = "org.AnnotationProgramming.Scan",
excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,value = {Repository.class}),
@ComponentScan.Filter(type = FilterType.ASPECTJ,pattern = "*..san1")})
public class Appconfig_Scan {
}
和上面一样只是excludeFilters 变为了includeFilters
@Configuration
@ComponentScan(basePackages = "org.AnnotationProgramming.Scan",
includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,value = {Repository.class})})
public class Appconfig_Scan {
}
注意:若只写@ComponentScan则默认扫描所有配置类,在创建工厂时也会把所有的配置类的类给创建出来
到目前位置有多种配置形式均可进行创建对象,那么这些配置形式的应用场合有哪些?
在@Component,@Bean,配置文件存在优先级
@Component<@Bean<配置文件
优先级高的可以覆盖优先级低的
例如:
提供一个Customer类
它id和name应该是NULL
@Component
public class Customer {
private String id;
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
接着在配置Bean中如下
@Configuration
@ComponentScan(basePackages = "org.AnnotationProgramming.Service")
@ImportResource("Applicontext_adv.xml")//后续会提到
public class Appconfig_adv {
@Bean
public Customer customer(){
Customer customer=new Customer();
customer.setName("SU");
customer.setId("1");
return customer;
}
}
按照之前说的应该会覆盖掉,那么创建工厂获取customer打印出运行结果为
2021-07-21 16:35:35 DEBUG DefaultListableBeanFactory:225 - Creating shared instance of singleton bean ‘appconfig_adv‘
2021-07-21 16:35:35 DEBUG DefaultListableBeanFactory:225 - Creating shared instance of singleton bean ‘customer‘
Customer{id=‘1‘, name=‘SU‘}
再接着再配置文件如下设置
<bean class="org.AnnotationProgramming.Service.Customer" id="customer">
<property name="id" value="2"/>
<property name="name" value="SY"/>
</bean>
按照之前说的应该会覆盖掉,那么创建工厂获取customer打印出运行结果为
2021-07-21 16:37:54 DEBUG DefaultListableBeanFactory:225 - Creating shared instance of singleton bean ‘appconfig_adv‘
2021-07-21 16:37:54 DEBUG DefaultListableBeanFactory:225 - Creating shared instance of singleton bean ‘customer‘
Customer{id=‘2‘, name=‘SY‘}
最重要的一点:每个配置形式的ID必须保持一致,比如我把@Component设置为id为CO
运行如下:
它会创建出@Bean对象而不是CO,也就不能进行覆盖
2021-07-21 16:39:59 DEBUG DefaultListableBeanFactory:225 - Creating shared instance of singleton bean ‘CO‘
2021-07-21 16:39:59 DEBUG DefaultListableBeanFactory:225 - Creating shared instance of singleton bean ‘customer‘
Customer{id=‘2‘, name=‘SY‘}
在上面配置Bean发现@ImportResource("Applicontext_adv.xml")有耦合,不符合开闭原则
也就是说,若以后要对配置Bean进行修改则要改动源代码
那么有以下解决方案
1.新建一个配置类,
Applicontext_adv.xml包含了需要覆盖的信息
如:
@Configuration
@ImportResource("Applicontext_adv.xml")
public class Appconfig_advNEW {
}
那么在获取工厂时如下:
ApplicationContext context = new AnnotationConfigApplicationContext(Appconfig_adv.class,Appconfig_advNEW.class);
设置多个参数,就可以整合在一起了同时在配置文件中自由设置。
最终解耦还是得用配置文件完成,但是配置Bean开发也有很多好处,都是相辅相成同时开发
为什么会有多个配置信息?
拆分多个配置bean的开发,是?种模块化开发的形式,也体现了?向对象各司其职的设计思想
可以整合哪几种?
关注点
方式一:直接在AnnotationConfigApplicationContext中填入多个配置Bean
如:
Appconfig
@Configuration
public class Appconfig {
@Bean
public User user1(){
User user=new User();
return user;
}
}
Appconfig1
@Configuration
public class Appconfig1 {
@Bean
public User user2(){
User user=new User();
return user;
}
}
工厂使用
ApplicationContext context = new AnnotationConfigApplicationContext(Appconfig.class,Appconfig1.class);
方式二:直接在AnnotationConfigApplicationContext中填入配置Bean所在的包
如:
ApplicationContext context = new AnnotationConfigApplicationContext("org.AnnotationProgramming.Configs");
方式三:使用@Import
如:在Appconfig3上面使用@Import
@Configuration
@Import(Appconfig1.class)
public class Appconfig3 {
@Bean
public User user3(){
User user=new User();
return user;
}
}
那么在使用的时候会获取Appconfig1的内容
工厂中只需要这么使用
ApplicationContext context = new AnnotationConfigApplicationContext(Appconfig3.class);
一二测试代码:
//测试多个配置文件整合
@Test
public void test() {
ApplicationContext context = new AnnotationConfigApplicationContext("org.AnnotationProgramming.Configs");
User user1= (User) context.getBean("user1");
User user2= (User) context.getBean("user2");
System.out.println("user1 = " + user1);
System.out.println("user2 = " + user2);
方式一二的结果都是一样的
都创建了user1和user2
2021-07-22 00:35:09 DEBUG DefaultListableBeanFactory:225 - Creating shared instance of singleton bean ‘user1‘
2021-07-22 00:35:09 DEBUG DefaultListableBeanFactory:225 - Creating shared instance of singleton bean ‘user2‘
方式三的测试代码
//测试@Improt
@Test
public void test11() {
ApplicationContext context = new AnnotationConfigApplicationContext(Appconfig3.class);
User user3= (User) context.getBean("user3");
User user2= (User) context.getBean("user2");
System.out.println("user3 = " + user3);
System.out.println("user2 = " + user2);
可以看见创建了user2,user3
2021-07-22 00:36:45 DEBUG DefaultListableBeanFactory:225 - Creating shared instance of singleton bean ‘user2‘
2021-07-22 00:36:45 DEBUG DefaultListableBeanFactory:225 - Creating shared instance of singleton bean ‘user3‘
方式一:不跨配置的注入
? 直接使用@Autowired在需要的变量上面注解就好
如:
Appconfig4
@Configuration
//不跨配置用
@Import(Appconfig5.class)
//跨配置时用
//@ImportResource("Applicontext_adv.xml")
public class Appconfig4 {
@Autowired
private UserDAO userDAO;
@Bean
public UserService userService(){
UserServiceImpl userService=new UserServiceImpl();
userService.setUserDAO(userDAO);
return userService;
}
}
Appconfig5
@Configuration
public class Appconfig5 {
@Bean
UserDAO userDAO(){
UserDAO userDAO=new UserDAOImpl();
return userDAO;
}
}
方式二:跨配置的注入
? 注释掉@Import 使用@ImportResource指定配置文件中创建的UserDAO对象
<bean id="userDAO" class="org.AnnotationProgramming.DAO.UserDAOImpl"/>
测试代码:
//测试注入
@Test
public void test12() {
ApplicationContext context = new AnnotationConfigApplicationContext(Appconfig4.class);
UserServiceImpl service = (UserServiceImpl) context.getBean("userService");
service.register();
}
运行结果:
都是一样的,可以看到UserDAOImpl.save被打印说明被执行,也就是注入成功
2021-07-22 00:45:28 DEBUG DefaultListableBeanFactory:225 - Creating shared instance of singleton bean ‘appconfig4‘
2021-07-22 00:45:28 DEBUG DefaultListableBeanFactory:225 - Creating shared instance of singleton bean ‘userDAO‘
2021-07-22 00:45:28 DEBUG DefaultListableBeanFactory:225 - Creating shared instance of singleton bean ‘userService‘
UserDAOImpl.save
如下:在之前有过,所以不过多介绍
@Configuration
//功能注解用
//@PropertySource("classpath:/init.properties")
//配置文件用context:property-placeholder
//@ImportResource("Applicontext_adv.xml")
public class Appconfig1 {
@Value("${id}")
private String id;
@Value("${name}")
private String name;
@Bean
public Customer customer(){
Customer customer= new Customer();
customer.setId(id);
customer.setName(name);
return customer;
}
这是在Spring配置文件中使用
如下设置;
<context:property-placeholder location="classpath:init.properties"/>
代码层面把上面的注释取消即可
当然了使用ClassPathXmlApplicationContext工厂也是可以的,不过需要先创建好Customer
配置互通
注意:
记得加上DTD约束
xmlns:context="http://www.springframework.org/schema/context"
#在xsi:schemaLocation加入
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
如下:其他和第二条一样
<bean id="holder" class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
<property name="location" value="init.properties"/>
如下:
? 需要指出的是必须是整合其他配置类,要不然读取不到配置文件内容
? 可能和配置类的CGlib代理有关,暂时不研究
@Configuration
@Import(Appconfig1.class)
public class holder {
@Bean
public PropertySourcesPlaceholderConfigurer configurer(){
PropertySourcesPlaceholderConfigurer configurer=new PropertySourcesPlaceholderConfigurer();
configurer.setLocation(new ClassPathResource("init.properties"));
return configurer;
}
}
测试代码:
@Test
//测试4种proerties的注入
public void test13() {
ApplicationContext context = new AnnotationConfigApplicationContext(Appconfig1.class);
// ApplicationContext context=new ClassPathXmlApplicationContext("/Applicontext_adv.xml");
Customer customer= (Customer) context.getBean("customer");
System.out.println(customer.toString());
}
结果都是
Customer{id=‘123‘, name=‘sy‘}
原文:https://www.cnblogs.com/ShanYu-Home/p/15042301.html