spring注解开发

1. 导入依赖

junit和spring-test

		<dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.1.16.RELEASE</version>
        </dependency>

2. 注解的作用

  • 可以通过在.java文件中添加注解,可以替代spring-config.xml配置文件中的数据源、组件扫描等文件
注解说明
@Configuration用于指定当前类是一个Spring配置类,当创建容器时会从该类上加载注解
@ComponentScan用于指定Spring在初始化容器时哟啊扫描的包,作用和Spring的xml配置文件中的<context:component-scan base-package=“com.lyx”/>一样
@Bean使用在方法上,标注将该方法的返回值存储到Spring容器中 ,如@Bean(“dataSource”),Spring会将当前方法的返回值以指定名称(dataSource)存储到Spring容器中
@PropertySource用来加载.properties文件中的配置,作用和Spring的xml配置文件中的 <context:property-placeholder location=“classpath:jdbc.properties”/>一样
@Import用于导入其他配置文件,作用和Spring的xml配置文件中的<import resource=“classpath:spring.xml”/>一样,@Import({XXX.class,XXX.xml})可以导入多个配置文件

3. 注解形式,给IOC容器中存放Bean


@Configuration、@ComponentScan、@Bean、@PropertySource、@Import


必须要有@Configuration注解(配置类)

3.1 注解替换Dao层

原xml文件如下,我们是不用写例如UserDaoImpl等UserDao的实现类的,使用注解开发却需要写,因为注解是添加在实现类上面

<?xml version="1.0" encoding="utf8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd"
>
    <bean id="user" class="com.lyx.entity.User">
        <property name="id" value="1"></property>
        <property name="city" value="China"></property>
    </bean>
</beans>

注解添加在实现类上面

import com.lyx.dao.UserDao;
import org.springframework.stereotype.Repository;

//替换xml文件的<bean id="userDao" class="com.lyx.entity.UserDao"></bean>
@Repository("userDao")//由于是Dao层,把@Component替换成@Repository
public class UserDaoImpl implements UserDao{
    public User queryUserById(int id){
        //数据库查询
    }
}

3.2 注解替换Service层


//替换xml文件的<bean id="userService" class="com.lyx.entity.UserService"></bean>
@Service("userService")//由于是Service,把@Component替换成@Service
public class UserServiceImpl implements UserService{
    
    @Resource(name="userDao")//跟Dao注解对应,替换原先注解@Autowired、@Qualifier("userDao")
    private UserDao userDao;
    public User queryUserById(int id){
        userDao.queryUserById(id);
    }
    //get和set方法也可以不写,
    
}

3.3 注解替换数据源

<?xml version="1.0" encoding="utf8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       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 "
>
    
    <!--    placeholder占位符-->
    <context:property-placeholder location="classpath:jdbc.properties"/>
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driverClass}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
        <property name="initialSize" value="${jdbc.init}"/>
        <property name="maxWait" value="60000"/>
        <property name="timeBetweenEvictionRunsMillis" value="50000"/>
        <property name="minEvictableIdleTimeMillis" value="3000"/>
    </bean>
    <context:component-scan base-package="com.lyx"/>
</beans>

DataSourceConfiguration.java

//标志该类是Spring的核心配置类
@Configuration
//替换xml文件的<context:property-placeholder location="classpath:jdbc.properties"/>
@PropertySource("classpath:jdbc.properties")
//替换xml文件的组件扫描<context:component-scan base-package="com.lyx"/>
@ComponentScan("com.lyx")
public class DataSourceConfiguration{
    @Bean("dataSource")//Spring会将当前方法的返回值以指定名称存储到Spring容器中
    public DataSource getDataSource() throws PropertyVetoException{
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName("${jdbc.driverClass}");
        dataSource.setUrl("${jdbc.url");
        dataSource.setUsername("${jdbc.username}");
        dataSource.setPassword("${jdbc.password}");
        return dataSource;
    }
}
  • 把上面的DataSourceConfiguration.java配置类,import导入SpringConfiguration.java类文件
@Configuration
@Import({DataSourceConfiguration.class})
public class SpringConfiguration{
    
}

3.4 扫描器:@ComponScan注解,给扫描指定规则

在这里插入图片描述
ctrl键进入excludeFilters看看如何定义不扫描
在这里插入图片描述
在这里插入图片描述
ctrl进入FilterType,看看过滤的类型都有哪些
在这里插入图片描述
在这里插入图片描述
看注释:

public enum FilterType {
    ANNOTATION, //按照注解过滤
    ASSIGNABLE_TYPE, //按照类型过滤
    ASPECTJ,//按照ASPECTJ表达式过滤
    REGEX,//按照正则表达式过滤
    CUSTOM;//按照自定义的过滤规则过滤
    private FilterType() {
    }
}

具体使用看这篇文章:Spring中FilterType的说明

ANNOTATION, 按照注解过滤
ASSIGNABLE_TYPE,按照类型过滤使用如下:
在这里插入图片描述

import com.lyx.mapper.StudentMapper;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Controller;

@Configuration
@ComponentScan(basePackages = "com.lyx",excludeFilters ={
        @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = Controller.class),
        @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,classes = StudentMapper.class)
      })
@PropertySource(value = "database.properties")
public class MyConfiguration {
}

测试一下:
在这里插入图片描述

public class test {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(MyConfiguration.class);
        String[] beanDefinitionNames = context.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println(beanDefinitionName);
        }
    }
}

再来看按照自定义类过滤CUSTOM:
先写一个自定义的类MyFilter
在这里插入图片描述

public class MyFilter implements TypeFilter {
    @Override
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        //如果扫描器扫描“com.lyx”包中的所有类,getClassName()方法可以拿到扫描的所有类名
        String className = classMetadata.getClassName();
     	//不要与学生相关的三层组件
        if(className.contains("Student")){
            return true;
        }
        return false;
    }
}

在这里插入图片描述

刚刚是过滤,现在来看只包含includeFilters
在这里插入图片描述

@Configuration
@ComponentScan(basePackages = "com.lyx",includeFilters ={
        @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = Controller.class),
        @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,classes = StudentMapper.class)
      },useDefaultFilters = false)
@PropertySource(value = "database.properties")
public class MyConfiguration {
}

3.5 条件注解@Conditional

  1. 自定义条件类MyConditional,只有满足以下条件,才把当前Bean放入容器中,必须实现Condition接口
    在这里插入图片描述
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;

public class MyCondition implements Condition {
    @Override
    public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
        //获取环境
        Environment environment = conditionContext.getEnvironment();
        String property = environment.getProperty("StudentServiceImpl.type");
        if (property.contains("Student")){
            return true;
        }
        return false;
    }
}

在这里插入图片描述

测试:
在这里插入图片描述
操作如下:
在这里插入图片描述
再次运行:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

注意:注解形式给IOC加入Bean,全部在Myconfiguraion类中,即添加注解@Configuration的类
在这里插入图片描述

4. 回顾一下给Ioc加入bean的方法

三层组件:通过扫描器@ComponentScan,三层注解:@Repository @Service @Controller

非三层组件:

  1. @Bean + 返回值
  2. @import
  3. FactoryBean(工厂Bean)

第一种方式@Bean+返回值已经说过了
现在来看@import的使用

5. @Import注入Bean

  1. 直接把需要放入SpringIOC容器中的编写到@Import中
    在这里插入图片描述
    测试一下是否放入:

     输出全部的bean
    

在这里插入图片描述
②自定义ImportSelector接口的实现类,通过selectimports方法实现。并且告知程序自己编写的实现类。@Import({Orange.class MyImportSelector.class})

在这里插入图片描述
在这里插入图片描述

import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;

public class MyImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        return new String[]{"com.lyx.entity.CourseFactory","com.lyx.aop.MyAround"};
    }
}

【selectImports()方法的返回值就是要纳入IoC容器的Bean】
在这里插入图片描述
最后来看第三种方式

6. FactoryBean注入Bean

  1. 自定义类MyFactoryBean,实现FactoryBean接口

在这里插入图片描述

package com.lyx.annotation;

import com.lyx.entity.Student;
import org.springframework.beans.factory.FactoryBean;

public class MyFactoryBean implements FactoryBean {
    @Override
    public Object getObject() throws Exception {
        return new Student();
    }

    @Override
    public Class<?> getObjectType() {
        return Student.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }
}
  1. 在MyConfiguration类中:添加注解@Import(value = {MyImportSelector.class})
    在这里插入图片描述
package com.lyx.annotation;

import com.lyx.entity.Classroom;
import com.lyx.entity.Student;
import com.lyx.mapper.StudentMapper;
import com.lyx.service.StudentService;
import com.lyx.service.impl.StudentServiceImpl;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.context.annotation.*;
import org.springframework.stereotype.Controller;

@Configuration
@ComponentScan(basePackages = "com.lyx",excludeFilters ={
        @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = Controller.class),
        @ComponentScan.Filter(type = FilterType.CUSTOM,value ={MyFilter.class})
      })
@PropertySource(value = "database.properties")
@Import(value = {MyImportSelector.class})
public class MyConfiguration {

      @Bean
      public FactoryBean<Student> myFactoryBean(){
            return new MyFactoryBean();
      }

      @Bean
      @Conditional(MyCondition.class)
      public StudentService getStudentServiceImpl(){
            return new StudentServiceImpl();
      }

}

测试一下:
在这里插入图片描述

public class test {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(MyConfiguration.class);
        String[] beanDefinitionNames = context.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println(beanDefinitionName);
        }
    }
}

当前方法把myFactoryBean放到容器中了??
我们尝试通过bean的id值来拿
在这里插入图片描述

public class test {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(MyConfiguration.class);
        Object myFactoryBean = context.getBean("myFactoryBean");
        System.out.println(myFactoryBean);
    }
}
//运行结果:Student{stuId=0, grade='null', Name='null', classId=0}

所以getBean拿到的是MyFactoryBean类中getObject()方法的返回值Student对象。
在这里插入图片描述
那么怎么拿MyFactoryBean对象呢
在getBean()时加上&符号

注意:需要通过&区分获取的对象是哪一个︰
不加&,获取的是最内部真实的Student;
如果加了&,获取的是FacotryBean

在这里插入图片描述

public class test {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context =
                new AnnotationConfigApplicationContext(MyConfiguration.class);
        Object myFactoryBean = context.getBean("&myFactoryBean");
        System.out.println(myFactoryBean);
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

素心如月桠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值