• 微信公众号:美女很有趣。 工作之余,放松一下,关注即送10G+美女照片!

10 Spring 高级注解编程一

开发技术 开发技术 3小时前 1次浏览

Spring 高级注解编程

1.@Configuration

一,作用

@Configuration用于定义配置类,替换掉xml配置文件

也就是说这个配置类就相当于配置文件

比如我创建一个Appconfig类指定为定义配置类就如下

@Configuration
public class Appconfig {
    xxx
}

二,使用

创建对象的工厂也有所不同

之前都是ClassPathXmlApplicationContext等等

现在变为了:AnnotationConfigApplicationContex

使用方法有两种:

  • ​ 反射

    ApplicationContext context =new AnnotationConfigApplicationContext(Appconfig.class);
    
  • 指定所在的包(Appconfig在AnnotationProgramming下面)

     ApplicationContext context= new AnnotationConfigApplicationContext("org/AnnotationProgramming");
    

2.@Bean

1.创建对象相关

@Bean注解在配置bean中进⾏使⽤,等同于XML配置⽂件中的

也有点类似@Component注解

一,使用@Bean创建简单对象

直接new出返回即可

@Bean
public User user(){
    return new User();
}

二,使用@Bean创建复杂对象

  • 在@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中如下实现

    ​ 简单来说步骤如下:

    1. 配置FactoryBean
    2. 在配置Bean中获取FactoryBean
    3. 从FactoryBean获得对象
    4. 返回对象
    @Bean
    public Connection connectionFactoryConfig() {
        ConnectionFactory connectionFactory=new ConnectionFactory();
        Connection connection= null;
        try {
            connection = connectionFactory.getObject();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return connection;
    }
    

三,使用@Scope控制生命周期

和之前的一样@Scope中的两个属性可以控制创建的时机

2.注入相关

1.自定义类型注入

我们得把需要注入的类型给创建出来

比如我要注入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;
}

2.JDK注入

方式一:

​ 直接手动设置,不过会有耦合问题

@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;
    }

3.@ComponentScan

@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种

  • .ANNOTATION value
  • .ASSIGNABLE_TYPE value
  • .ASPECTJ pattern
  • .REGEX pattern
  • .CUSTOM value

4.value和pattern

  • 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则默认扫描所有配置类,在创建工厂时也会把所有的配置类的类给创建出来

4.配置的优先级

一,配置的应用场景

到目前位置有多种配置形式均可进行创建对象,那么这些配置形式的应用场合有哪些?

  1. @Component 用于自行开发,也就是自己开发的类
  2. @Bean 用于二次开发,比如别人开发的类
  3. 配置文件的标签
  4. @Import 用于对Spring底层开发

二,配置的优先级

在@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开发也有很多好处,都是相辅相成同时开发

5.跨配置整合

一,为什么要整合

  1. 为什么会有多个配置信息?

    拆分多个配置bean的开发,是⼀种模块化开发的形式,也体现了⾯向对象各司其职的设计思想

  2. 可以整合哪几种?

    • @Component相关注解的
    • 配置Bean
    • XML配置文件
  3. 关注点

    • 如何使多配置的信息 汇总成⼀个整体
    • 如何实现跨配置的注⼊

二, 多个配置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

6.4种配置文件的使用总结

一,@PropertySource()

如下:在之前有过,所以不过多介绍

@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;
    }

二,context:property-placeholder

这是在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

三,PropertySourcesPlaceholderConfigurer类在配置文件

如下:其他和第二条一样

<bean id="holder" class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
    <property name="location" value="init.properties"/>

四,PropertySourcesPlaceholderConfigurer类在@Bean

如下:

​ 需要指出的是必须是整合其他配置类,要不然读取不到配置文件内容

​ 可能和配置类的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'}

程序员灯塔
转载请注明原文链接:10 Spring 高级注解编程一
喜欢 (0)