【Spring】二、IoC(中)(注解管理、反射)

IoC(中)(注解管理、反射)

基于注解管理bean

注解是 @注解名(属性)的格式,是Java中的一种特殊标记

Spring通过注解实现自动装配的方式:

引入依赖-开启组件扫描-使用注解定义Bean-依赖注入

开启组件扫描

Spring默认不支持使用注解进行自动装配,所以要进行配置,开启组件扫描是为了让java扫描注解并实现相应功能。

在bean.xml文件下的beans标签中增加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
       http://www.springframework.org/schema/beans/spring-beans.xsd

       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">

在beans标签下配置context

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

也有扫描排除和仅扫描某些注解的配置方式,这里不做介绍。

使用注解定义Bean

下面四种注解都可以用来将类标注为SpringBean,其功能一致,只是使用位置不同。

@Component 可以使用在所有层中,但一般用于Java Bean

@Repository 一般使用在Dao层

@Service 通常用于Service层

@Controller 通常用于Controller层

演示如下:

@Component(value = "user")  //相当于<bean id=""user" class="...">

若value值不写,默认生成类名首字母小写的value

属性注入

在属性名上添加@Autowired注解,完成对属性的依赖注入,这是根据属性的类型自动找到IoC容器中的Bean进行注入的(由于类前的注解,类对象已经被添加进IoC容器中了)。

示例:

//用来向IoC容器中添加UserController的对象
@Controller
public class UserController {

    //自动在容器中找到UserServcie类型的对象并进行注入
    //在UserService中也类似进行注解
    @Autowired
    private UserService userService;

    public void add() {
        System.out.println("Do Controller.............");
        userService.add();
    }
}

set注入、构造注入、形参注入

将@Autowired添加到属性对应的set方法与构造器上,也可以实现对应属性的注入。

    private UserDao userDao;

	//set方法上的注解
    @Autowired
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    private UserDao userDao;

	//构造器上的注解
    @Autowired
    public UserServiceImpl(UserDao userDao) {
        this.userDao = userDao;
    }

甚至@Autowired还可以用到形参中,也可以实现依赖注入:

    private UserDao userDao;

	//在形参前使用
    public UserServiceImpl(@Autowired UserDao userDao) {
        this.userDao = userDao;
    }

注意:若类中只有一个有参构造函数时,@Autowired可以省略

根据名称进行注入

当接口有多个实现类时,仅仅有@Autowired注解就无法实现依赖注入了(不知道该注入哪个实现类)

这个时候就会用到@Qualifier注解,Qualifier的value值为要注入的对象的类名的首字母小写。

    @Autowired
    @Qualifier(value = "userRedisDaoImpl")
    private UserDao userDao;

@Repository
public class UserRedisDaoImpl implements UserDao{

    @Override
    public void add() {
        System.out.println("Do Redis......................");
    }
}

@Resource注入

配置依赖

<!--    @Resouce注解的依赖配置-->
    <dependencies>
        <dependency>
            <groupId>jakarta.annotation</groupId>
            <artifactId>jakarta.annotation-api</artifactId>
            <version>2.1.1</version>
        </dependency>
    </dependencies>

@Resource注解是JDK拓展包的一部分,除了JDK8到JDK11的版本,其他版本都需要添加依赖才可以使用

@Resource注解使用在属性名或者set方法上,其默认通过名称进行注入,会寻找和@Resource(name = “xxx”)中name相同的类上的注解,若没有写name属性的话,会默认按照需要注入的属性名进行寻找,若仍然找不到,则会按照类型寻找。

//该value与测试文件中的getBean()对应
@Controller(value = "myUserController")
public class UserController {
    @Resource
    private UserService userService;
//该value与UserController中的@Resource对应,其没有生命name值,默认为userService,与该类对应
@Service(value = "userService")
public class UserServiceImpl implements UserService {

    @Resource(name = "myUserDao")
    private UserDao userDao;
//该value与UserServiceImpl的@Resource对应,其value值等于Resource中的name值
@Repository(value = "myUserDao")
public class UserDaoImpl implements UserDao {
    @Override
    public void add() {
        System.out.println("Do Dao...............");
    }
}

全注解开发

使用配置类代替配置文件实现全注解开发

创建配置类:

@Configuration //配置类的声明
@ComponentScan("com.qinghe.spring6")    //开启组件扫描
public class SpringConfig {
}

在测试中创建的IoC容器有所改变:

public class TestUserControllerAnno {
    public static void main(String[] args) {
        //创建不同的实现类并传入配置文件的类
        ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
        UserController myUserController = context.getBean("myUserController", UserController.class);
        myUserController.add();
    }
}

反射回顾

反射就是通过在运行时的类,可以获取他的类名、属性和方法并加以使用的技术。

通过反射获取类名并创建对象:

    //获取对象的多种方式
	@Test
    public void test01() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        //类名.class
        Class clazz1 = Car.class;

        //对象.getClass()
        Class clazz2 = new Car().getClass();

        //Class.forName("全路径")
        Class clazz3 = Class.forName("com.qinghe.reflect.Car");

        //创建对象
        Car car = (Car) clazz3.getDeclaredConstructor().newInstance();
        System.out.println(car);
    }

通过获取构造器的方式创建对象

   @Test
    public void test02() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        Class clazz = Car.class;

        //获取clazz类的所有构造器
        //直接get的方法无法获取私有的方法或构造器
        Constructor[] constructor = clazz.getConstructors();

        //若要获取私有的方法,则需要使用getDeclaredConstructor()
        Constructor[] constructor1 = clazz.getConstructors();

        //遍历一遍得到的构造器
        for(Constructor c : constructor1) {
            System.out.println("方法名称:" + c.getName() + " 参数个数:" + c.getParameterCount());    //输出构造器的名字
        }

        //使用获取到的构造器创建对象
//        Constructor c = clazz.getConstructor(String.class, int.class, String.class);
//        Car car = (Car)c.newInstance("宾利", 50, "黑色");
//        System.out.println(car);

        //若构造器为私有,使用getDeclaredConstructor()获取
        Constructor c1 = clazz.getDeclaredConstructor(String.class, int.class, String.class);
        c1.setAccessible(true);     //令私有允许访问
        c1.newInstance("路虎", 90, "帝王金");
        System.out.println(c1);
    }

反射获取属性与设置属性的方法

   @Test
    public void test03() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        //获取字节码文件
        Class clazz = Car.class;
        
        //获取构造器,创建对象
        Car car = (Car)clazz.getDeclaredConstructor().newInstance();

        //获取所有的属性,并存储在一个数组中
        Field[] fields = clazz.getDeclaredFields();
        
        //遍历所有属性
        for (Field field : fields) {
            
            //设置name属性
            if(field.getName().equals("name")) {
                //令私有属性可被修改
                field.setAccessible(true);
                
                //设置属性,对象与属性内容
                field.set(car, "宝马");
            }
            System.out.println(field.getName());
        }
        System.out.println(car);
    }

反射获取方法的方法

   @Test
    public void test04() throws InvocationTargetException, IllegalAccessException {
        Car car = new Car("劳斯莱斯", 900000, "彩虹色");
        Class clazz = car.getClass();

        Method[] methods = clazz.getDeclaredMethods();
        for (Method method : methods) {
            System.out.println(method.getName());
            if (method.getName().equals("toString")) {
                method.setAccessible(true);
                //.incoke()的第一个参数要传对象,若该方法还需求参数,则要在后面写跟上
                String invoke = (String)method.invoke(car);
                System.out.println("toString方法执行了:" + car);
            }
        }
    }

注意.getDeclaredMethods()可以获取类中所有定义的方法(包括私有)

.getMethods()会获取所有public方法(无法获取私有),同时也会获取父类中的所有方法

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值