[SSM]Spring IoC注解式开发

目录

十二、Spring IoC注解式开发

12.1回顾注解

12.1.1自定义注解

12.1.2使用注解

12.1.3通过反射机制读取注解

12.2声明Bean的注解

12.3Spring注解的使用

12.4选择性实例化Bean

12.5负责注入的注解

12.5.1@Value

12.5.2@Autowired与@Qualifier

12.5.3@Resource

12.6全注解式开发


十二、Spring IoC注解式开发

12.1回顾注解

  • 注解的存在主要是为了简化XML的配置,Spring6倡导全注解开发。

12.1.1自定义注解
package com.hhb.annotation;
​
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
​
/**
 * 自定义注解
 */
//标注注解的注解叫做元注解。@Target注解用来修饰@Component可以出现的位置
//以下表示@Component注解可以出现在类上、属性上
//@Target(value = {ElementType.TYPE, ElementType.FIELD})
//以下表示@Component注解可以出现在类上
//@Target(value = {ElementType.TYPE})
//使用注解的时候,如果注解的属性是value的话,value可以省略
//@Target({ElementType.TYPE})
//使用某个注解的时候,如果注解的属性值是数组,并且数组中只有一个元素,大括号可以省略
@Target(ElementType.TYPE)
//@Retention也是一个元注解,用来标注@Component注解最终保留在class文件当中,并且可以被反射机制读取。
@Retention(RetentionPolicy.RUNTIME)
public @interface Component {
    //定义注解的属性,String是属性类型,value是属性名
    String value();
    //数组属性,String[]是属性类型,names是属性名
    //String[] names();
}
  • 以上是自定义的一个注解:Component

  • 该注解上面修饰的注解包括:Target注解和Retention注解,这两个注解被称为元注解。

  • Target注解用来设置Component注解可以出现的位置,以上代表表示Component注解只能在类和接口上。

  • Retention注解用来设置Component注解的保持性策略,以上代表Component注解可以被反射机制读取。

12.1.2使用注解
package com.hhb.bean;
​
import com.hhb.annotation.Component;
​
//@Component(属性名=属性值,属性名=属性值,...)
//@Component(value = "userBean")
//如果属性名是value,value可以省略
@Component("userBean")
public class User {
    //编译器报错,不能出现在这里
    //@Component(value = "test")
    //private String name;
}

测试

package com.hhb.client;
​
import com.hhb.annotation.Component;
​
public class ReflectAnnotation {
    public static void main(String[] args) throws Exception{
        //通过反射机制怎么获取注解
        //获取类
        Class<?> aClass = Class.forName("com.hhb.bean.User");
        //判断类上面有没有这个注解
        if (aClass.isAnnotationPresent(Component.class)) {
            //获取类上的注解
            Component annotation = aClass.getAnnotation(Component.class);
            //访问注解属性
            System.out.println(annotation.value());
        }
    }
}
12.1.3通过反射机制读取注解
  • 当Bean类上有Component注解时,则实例化Bean对象,如果没有,则不实例化对象。

有注解的Bean

package com.hhb.bean;
​
import com.hhb.annotation.Component;
​
@Component("vipBean")
public class Vip {
}

没有注解的Bean

package com.hhb.bean;
​
public class Order {
}

反射解析注解

package com.hhb.client;
​
import com.hhb.annotation.Component;
​
import java.io.File;
import java.net.URL;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
​
public class ComponentScan {
    public static void main(String[] args) {
        Map<String, Object> beanMap = new HashMap<>();
        //目前只知道一个包的名字,扫描这个包下所有的类,当这个类上有@component注解的时候,实例化该对象,然后放到Map集合中
        String packageName = "com.hhb.bean";
        //开始写扫描程序
        //使用正则表达式,将packageName中的 . 替换成 /
        String packagePath = packageName.replaceAll("\\.", "/");
        //com是在类的根路径下的一个目录
        URL url = ClassLoader.getSystemClassLoader().getResource(packagePath);
        String path = url.getPath();
        //获取一个绝对路径下的所有文件
        File file = new File(path);
        File[] files = file.listFiles();
        Arrays.stream(files).forEach(f -> {
            try {
                String className = packageName + "." + f.getName().split("\\.")[0];
                //通过反射机制解析注解
                Class<?> aClass = Class.forName(className);
                //判断类上是否有这个注解
                if (aClass.isAnnotationPresent(Component.class)) {
                    //获取注解
                    Component annotation = aClass.getAnnotation(Component.class);
                    String id = annotation.value();
                    //创建对象
                    Object obj = aClass.newInstance();
                    beanMap.put(id,obj);
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        });
        System.out.println(beanMap);
    }
}

执行结果


12.2声明Bean的注解

  • 负责声明Bean的注解,常见的包括四个:

    • @Component

    • @Controller

    • @Service

    • @Repository

  • @Controller、@Service、@Repository这三个注解都是@Component注解的别名,也就是说,这四个注解的功能都一样,用哪个都可以。

  • 为了增强程序的可读性,建议:

    • 控制器类上使用:Controller

    • service类上使用:Service

    • dao类上使用:Repository

  • 他们都是只有一个value属性,value属性用来指定bean的id,也就是bean的名字。

 

 

12.3Spring注解的使用

第一步:加入aop的依赖

 

第二步:在配置文件中添加context命名空间

<?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 htt
p://www.springframework.org/schema/beans/spring-beans.xsd
 http://www.springframework.org/schema/context ht
tp://www.springframework.org/schema/context/spring-context.xsd">
</beans>

第三步:在配置文件中指定要扫描的包

<context:component-scan base-package="com.hhb.bean"/>

第四步:在Bean类上使用注解

package com.hhb.bean;
​
import org.springframework.stereotype.Service;
​
@Service(value = "orderBean")
public class Order {
}
package com.hhb.bean;
​
import org.springframework.stereotype.Controller;
​
@Controller
public class Student {
}

测试

@Test
public void testBeanComponent() {
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
    User userBean = applicationContext.getBean("userBean", User.class);
    System.out.println(userBean);
​
    Order orderBean = applicationContext.getBean("orderBean", Order.class);
    System.out.println(orderBean);
​
    Student student = applicationContext.getBean("student", Student.class);
    System.out.println(student);
​
    Vip vip = applicationContext.getBean("vip", Vip.class);
    System.out.println(vip);
}
  • 如果注解的属性名是value,那么value可以省略。

  • 如果将value属性彻底去掉,spring会被Bean自动取名,默认名字为:Bean类名首字母小写即可。

  • 如果是多个包,有两种解决方案

    • 在配置文件中指定多个包,用逗号隔开。

    • <context:component-scan base-package="com.hhb.dao,com.hhb.bean"/>
    • 指定多个包的共同父包。(会降低效率)

    • <context:component-scan base-package="com.hhb"/>

12.4选择性实例化Bean

<?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 http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
​
    <!--第一种解决方案:
        use-default-filters="false"
        如果这个属性是false,表示com.hhb.bean2包下所有的带有声明Bean的注解全部失效
    -->
        <context:component-scan base-package="com.hhb.bean2" use-default-filters="false">
            <!--只有@Repository被包含进来生效--> 
            <context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
        </context:component-scan>
    <!--第二种解决方案:
         use-default-filters="true"
         如果这个属性的值是true,表示com.hhb.bean2下的所有的带有声明Bean的注解全部生效
         use-default-filters="true" 默认值是true,不用写
    -->
    <context:component-scan base-package="com.hhb.bean2" use-default-filters="true">
        <!--@Repository注解失效-->
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
    </context:component-scan>
​
</beans>

12.5负责注入的注解

  • @Component、@Controller、@Service、@Repository这四个注解是用来声明Bean的,声明后这些Bean将被实例化。

  • 给Bean属性赋值需要使用这些注解:

    • @Value

    • @Autowired

    • @Qualifier

    • @Resource

12.5.1@Value
  • 当属性的类型是简单类型时,可以使用@Value注解进行注入。

Product

package com.hhb.bean3;
​
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
​
@Component
public class Product {
    @Value("苹果")
    private String name;
    @Value("5")
    private int num;
​
    public void setName(String name) {
        this.name = name;
    }
​
    public void setNum(int num) {
        this.num = num;
    }
​
    @Override
    public String toString() {
        return "Product{" +
                "name='" + name + '\'' +
                ", num=" + num +
                '}';
    }
}
  • @Value注解可以直接使用在属性上,也可以使用在setter方法上,也可以使用在构造方法中。

  • 当@Value注解使用在属性上时,可以不用写setter方法。

public Product(@Value("苹果") String name, @Value("5") int num) {
    this.name = name;
    this.num = num;
}

spring-di-annotation.xml

<?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 http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
​
    <context:component-scan base-package="com.hhb.bean3"/>
​
</beans>

测试

@Test
public void testDI() {
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-di-annotation.xml");
    Product product = applicationContext.getBean("product", Product.class);
    System.out.println(product);
}
12.5.2@Autowired与@Qualifier
  • @Autowired注解可以用来注入非简单类型,被翻译为:自动连线的或者自动装配的。

  • 单独使用@Autowired注解,默认根据类型装配。(默认是byType)

  • @Autowired可以标注在哪里?

    • 构造方法上

    • 方法上

    • 形参上

    • 注解上

    • 属性上

OrderDao接口

package org.hhb.dao;
​
public interface OrderDao {
    void insert();
}

OrderDaoForMySQL

package org.hhb.dao.impl;
​
import org.hhb.dao.OrderDao;
import org.springframework.stereotype.Repository;
​
@Repository
public class OrderDaoForMySQL implements OrderDao {
    @Override
    public void insert() {
        System.out.println("mysql~~~");
    }
}
  • 构造方法和setter方法都没有提供,在属性上使用@Autowired注解,注入成功。

  • @Autowired注解可以出现在setter方法上。

  • @Autowired注解可以出现在构造方法上。

  • @Autowired注解可以出现在构造方法的形参上。

  • 当有参数的构造方法只有一个时,@Autowired注解可以省略。

OrderService

package org.hhb.service.impl;
​
import org.hhb.dao.OrderDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
​
@Service
public class OrderService {
    @Autowired
    private OrderDao orderDao;
​
    public void setOrderDao(OrderDao orderDao) {
        this.orderDao = orderDao;
    }
​
    public void generate() {
        orderDao.insert();
    }
}
  • Autowired注解默认是byType进行注入的,也就是说根据类型注入的,如果以上程序中,OrderDao接口还有另外一个实现类,会出现问题。

  • 解决方案:@Autowired注解和@Qualifier注解联合起来才可以根据名称进行装配,在@Qualifier注解中指定Bean名称。

package org.hhb.service.impl;
​
import org.hhb.dao.OrderDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
​
@Service
public class OrderService {
    @Autowired
    @Qualifier("orderDaoForOracle")
    private OrderDao orderDao;
​
    public void setOrderDao(OrderDao orderDao) {
        this.orderDao = orderDao;
    }
​
    public void generate() {
        orderDao.insert();
    }
}
12.5.3@Resource
  • @Resource注解也可以完成非简单类型注入,它和@Autowired注解有什么区别?

    • @Resource注解是JDK扩展包中的,也就是说属于JDK的一部分。所以该注解是标注注解,更加具有通用性。

    • @Autowired注解是Spring框架自己的。

    • @Autowired注解默认根据名称装配byName,未指定name时,使用属性名作为name。通过name找不到的话会自动启动通过类型byType装配。

    • @Autowired注解默认根据类型装配byType,如果想根据名称装配,需要配合@Qualifier注解一起用。

    • @Resource注解用在属性上、setter方法上。

    • @Autowired注解用在属性上、setter方法上、构造方法上、构造方法参数上。

  • @Resource注解属于JDK扩展包,所以不在JDK当中,需要额外引入以下依赖:如果是JDK8的话不需要额外引入依赖,高于JDK11或低于JDK8需要引入以下依赖。

<dependency>
 <groupId>jakarta.annotation</groupId>
 <artifactId>jakarta.annotation-api</artifactId>
 <version>2.1.1</version>
</dependency>

UserDaoForMySQL

package org.hhb.dao.impl;
​
import org.hhb.dao.OrderDao;
import org.springframework.stereotype.Repository;
​
@Repository("orderDao")
public class OrderDaoForMySQL implements OrderDao {
​
    @Override
    public void insert() {
        System.out.println("mysql~~~");
    }
}

OrderService

package org.hhb.service.impl;
​
import jakarta.annotation.Resource;
import org.hhb.dao.OrderDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
​
@Service
public class OrderService {
    @Resource(name = "orderDao")
    private OrderDao orderDao;
​
    public void setOrderDao(OrderDao orderDao) {
        this.orderDao = orderDao;
    }
​
    public void generate() {
        orderDao.insert();
    }
}

12.6全注解式开发

  • 所谓的全注解开发就是不再使用spring配置文件了,写一个配置类来代替配置文件。

Spring6Config

package org.hhb;
​
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
​
//编写一个类,代替Spring框架的配置文件
@Configuration
@ComponentScan({"org.hhb.dao", "org.hhb.service"})
public class Spring6Config {
}

测试

@Test
public void testNoXML(){
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Spring6Config.class);
    OrderService orderService = context.getBean("orderService", OrderService.class);
    orderService.generate();
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Ja kar ta

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

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

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

打赏作者

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

抵扣说明:

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

余额充值