Spring(下)

2023-04-26 18:35:39 浏览数 (1)

4. 基于XML管理Bean

4.13 FactoryBean

4.13.1 FactoryBean位置

4.13.2 实现

  • 项目结构
  • User
代码语言:javascript复制
package com.example.bean;

public class User {
    private Integer id;

    private String name;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{"  
                "id="   id  
                ", name='"   name   '''  
                '}';
    }
}
  • UserFactoryBean
代码语言:javascript复制
package com.example.factory;

import com.example.bean.User;
import org.springframework.beans.factory.FactoryBean;

public class UserFactoryBean implements FactoryBean<User> {
    @Override
    public User getObject() throws Exception {
        return new User();
    }

    @Override
    public Class<?> getObjectType() {
        return User.class;
    }
}
  • bean.xml
代码语言:javascript复制
<?xml version="1.0" encoding="UTF-8"?>
<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 class="com.example.bean.User">
        <property name="id" value="1001"></property>
        <property name="name" value="admin"></property>
    </bean>

    <bean id="factory" class="com.example.factory.UserFactoryBean"></bean>
</beans>
  • UserFactoryBeanTest
代码语言:javascript复制
import com.example.bean.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class UserFactoryBeanTest {
    @Test
    public void testUserFactoryBean(){
        //获取IOC容器
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        User user = (User) ac.getBean("factory");
        System.out.println(user);
    }
}

4.14 基于xml自动装配

  • 自动装配:根据指定的策略,在IOC容器中匹配某一个bean,自动为指定的bean中所依赖的类类型或接口类型属性赋值
  • 使用bean标签的autowire属性设置自动装配效果
  • 自动装配方式:byType

byType:根据类型匹配IOC容器中的某个兼容类型的bean,为属性自动赋值 若在IOC中,没有任何一个兼容类型的bean能够为属性赋值,则该属性不装配,即值为默认值null 若在IOC中,有多个兼容类型的bean能够为属性赋值,则抛出异常NoUniqueBeanDefinitionException

  • 自动装配方式:byName

byName:将自动装配的属性的属性名,作为bean的id在IOC容器中匹配相对应的bean进行赋值???

  • 实现

UserDao

代码语言:javascript复制
package com.example.dao;

public interface UserDao {
    void saveUser();
}

UserDaoImpl

代码语言:javascript复制
package com.example.dao.impl;

import com.example.dao.UserDao;

public class UserDaoImpl implements UserDao {
    public void saveUser(){
        System.out.println("save user....");
    }
}

UserService

代码语言:javascript复制
package com.example.service;

public interface UserService {
    void saveUser();
}

UserServiceImpl

代码语言:javascript复制
package com.example.service.impl;

import com.example.dao.UserDao;
import com.example.service.UserService;

public class UserServiceImpl implements UserService {
    private UserDao userDao;

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public void saveUser() {
        userDao.saveUser();
    }
}

UserController

代码语言:javascript复制
package com.example.controller;

import com.example.service.UserService;

public class UserController {
    private UserService userService1;

    public void setUserService(UserService userService) {
        this.userService1 = userService;
    }

    public void saveUser(){
        userService1.saveUser();
    }
}

beanByType.xml

代码语言:javascript复制
<?xml version="1.0" encoding="UTF-8"?>
<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">

    <!-- 自动装配 byType -->
    <bean id="userController" class="com.example.controller.UserController" autowire="byType"></bean>
    <bean id="userService" class="com.example.service.impl.UserServiceImpl" autowire="byType"></bean>
    <bean id="userDao" class="com.example.dao.impl.UserDaoImpl"></bean>

</beans>

beanByName.xml

代码语言:javascript复制
<?xml version="1.0" encoding="UTF-8"?>
<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">

    <!-- 自动装配 byName -->
    <bean id="userController" class="com.example.controller.UserController" autowire="byName"></bean>

    <bean id="userService" class="com.example.service.impl.UserServiceImpl" autowire="byName"></bean>
<!--    <bean id="userServiceImpl" class="com.example.service.impl.UserServiceImpl" autowire="byName"></bean>-->

    <bean id="userDao" class="com.example.dao.impl.UserDaoImpl"></bean>
<!--    <bean id="userDaoImpl" class="com.example.dao.impl.UserDaoImpl"></bean>-->
</beans>

AutoTest

代码语言:javascript复制
import com.example.controller.UserController;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AutoTest {
    @Test
    public void testByType(){
        ApplicationContext app = new ClassPathXmlApplicationContext("beanByType.xml");
        UserController userController = app.getBean(UserController.class);
        userController.saveUser();
    }

    @Test
    public void testByName(){
        ApplicationContext app = new ClassPathXmlApplicationContext("beanByName.xml");
        UserController userController = app.getBean(UserController.class);
        userController.saveUser();
    }
}

4.15 工厂方法实例化

代码语言:javascript复制
<!-- 工厂静态方法实例化-->
<bean id="userDaoStaticFactory" class="com.example.factory.UserStaticFactory" factory-method="getUserDao" scope="prototype"></bean>

<!-- 工厂动态方法实例化-->
<bean id="factory" class="com.example.factory.UserDynamicFactory" scope="prototype"></bean>
<bean id="userDaoDynamicFactory" factory-bean="factory" factory-method="getUserDao" scope="prototype"></bean>
  • UserStaticFactory
代码语言:javascript复制
package com.example.factory;

import com.example.dao.UserDao;
import com.example.dao.impl.UserDaoImpl;

public class UserStaticFactory {
    public static UserDao getUserDao(){
        System.out.println("StaticFactory:getUserDao...");
        return new UserDaoImpl();
    }
}
  • UserDynamicFactory
代码语言:javascript复制
package com.example.factory;

import com.example.dao.UserDao;
import com.example.dao.impl.UserDaoImpl;

public class UserDynamicFactory {
    public UserDao getUserDao(){
        return new UserDaoImpl();
    }
}

5. 基于注解管理Bean

5.1 组件扫描

5.1.1 基础

  • 开启组件扫描
代码语言:javascript复制
<context:component-scan base-package="com.example"></context:component-scan>
  • type:扫描类型
  • context:exclude-filter标签:排除
代码语言:javascript复制
<context:component-scan base-package="com.example">
    <!-- type="annotation",根据注解排除,expression中设置要排除的注解的全类名 -->
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Component"/>

    <!-- type="assignable",根据类型排除,expression中设置要排除的类型的全类名 -->
    <!--<context:exclude-filter type="assignable" expression="com.example.bean.User"/>-->
</context:component-scan>
  • context:include-filter标签:指定在原有扫描规则的基础上追加的规则
  • use-default-filters属性:取值false表示关闭默认扫描规则。要指定包含的注解,必须设置use-default-filters="false",因为默认规则即扫描指定包下所有类
代码语言:javascript复制
<context:component-scan base-package="com.example" use-default-filters="false">
    <!-- type="annotation",根据注解包含,expression中设置要包含的注解的全类名 -->
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/>

    <!-- type="assignable",根据类型包含,expression中设置要包含的类型的全类名 -->
    <!--  <context:include-filter type="assignable" expression="com.example.bean.User"/> -->
</context:component-scan>

5.1.2 实现

  • 项目结构
  • Person
代码语言:javascript复制
package com.example.bean;

import org.springframework.stereotype.Repository;

@Repository
public class Person {
}
  • User
代码语言:javascript复制
package com.example.bean;

import org.springframework.stereotype.Component;

@Component
public class User {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
  • exclude-bean.xml
代码语言:javascript复制
<?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
                          https://www.springframework.org/schema/context/spring-context.xsd
                          ">

    <!-- 开启组件扫描 -->
    <context:component-scan base-package="com.example">
        <!-- type:设置排除或包含的依据 -->

        <!-- type="annotation",根据注解排除,expression中设置要排除的注解的全类名 -->
        <!-- <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Component"/>  -->

        <!-- type="assignable",根据类型排除,expression中设置要排除的类型的全类名 -->
        <!-- <context:exclude-filter type="assignable" expression="com.example.bean.User"/> -->

    </context:component-scan>


</beans>
  • include-bean.xml
代码语言:javascript复制
<?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
                          https://www.springframework.org/schema/context/spring-context.xsd
                          ">
     <!-- 开启组件扫描 -->
    <context:component-scan base-package="com.example" use-default-filters="false">

        <!--
            context:include-filter标签:指定在原有扫描规则的基础上追加的规则
            use-default-filters属性:取值false表示关闭默认扫描规则
            要指定包含的注解,必须设置use-default-filters="false",因为默认规则即扫描指定包下所有类
        -->

        <!-- type="annotation",根据注解包含,expression中设置要包含的注解的全类名 -->
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/>

        <!-- type="assignable",根据类型包含,expression中设置要包含的类型的全类名 -->
        <!--  <context:include-filter type="assignable" expression="com.example.bean.User"/> -->

    </context:component-scan>


</beans>
  • ComponentScanTest
代码语言:javascript复制
import com.example.bean.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class ComponentScanTest {
    @Test
    public void test(){
        ApplicationContext app = new ClassPathXmlApplicationContext("exclude-bean.xml");
        User user = app.getBean("user", User.class);
        user.setName("张三");
        System.out.println(user.getName());


        ApplicationContext app2 = new ClassPathXmlApplicationContext("include-bean.xml");
        User user2 = app2.getBean("user", User.class);
        user2.setName("李四");
        System.out.println(user2.getName());
    }
}

5.1.3 使用注解定义 Bean

Spring 提供了以下多个注解,这些注解可以直接标注在 Java 类上,将它们定义成 Spring Bean。

注解

说明

@Component

该注解用于描述 Spring 中的 Bean,它是一个泛化的概念,仅仅表示容器中的一个组件(Bean),并且可以作用在应用的任何层次,例如 Service 层、Dao 层等。 使用时只需将该注解标注在相应类上即可。

@Repository

该注解用于将数据访问层(Dao 层)的类标识为 Spring 中的 Bean,其功能与 @Component 相同。

@Service

该注解通常作用在业务层(Service 层),用于将业务层的类标识为 Spring 中的 Bean,其功能与 @Component 相同。

@Controller

该注解通常作用在控制层(如SpringMVC 的 Controller),用于将控制层的类标识为 Spring 中的 Bean,其功能与 @Component 相同。

5.2 Autowired

  • 单独使用@Autowired注解,默认根据类型装配。【默认是byType】
代码语言:javascript复制
package org.springframework.beans.factory.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
    boolean required() default true;
}

源码中有两处需要注意:

  • 第一处:该注解可以标注在:构造方法上、方法上、形参上、属性上、注解上
  • 第二处:该注解有一个required属性,默认值是true,表示在注入的时候要求被注入的Bean必须是存在的,如果不存在则报错。如果required属性设置为false,表示注入的Bean存在或者不存在都没关系,存在的话就注入,不存在的话,也不报错。

5.2.1 属性上

  • UserDao
代码语言:javascript复制
package com.example.dao;

public interface UserDao {
    void addUser();
}
  • UserDaoImpl
代码语言:javascript复制
package com.example.dao.impl;

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

@Repository
public class UserDaoImpl implements UserDao {
    @Override
    public void addUser() {
        System.out.println("add user....");
    }
}
  • UserService
代码语言:javascript复制
package com.example.service;

public interface UserService {
    void addUser();
}
  • UserServiceImpl
代码语言:javascript复制
package com.example.service.impl;

import com.example.dao.UserDao;
import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserDao userDao;

    @Override
    public void addUser() {
        userDao.addUser();
    }
}
  • UserController
代码语言:javascript复制
package com.example.controller;

import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller
public class UserController {
    @Autowired
    private UserService userService;

    public void addUser(){
        userService.addUser();
    }
}
  • property-bean.xml
代码语言:javascript复制
<?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 https://www.springframework.org/schema/context/spring-context.xsd">
    <!-- 开启组件扫描 -->
    <context:component-scan base-package="com.example"></context:component-scan>
</beans>
  • AutowiredTest
代码语言:javascript复制
import com.example.controller.UserController;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class AutowiredTest {
    @Test
    public void test(){
        ApplicationContext app = new ClassPathXmlApplicationContext("property-bean.xml");
        UserController userController = app.getBean(UserController.class);
        userController.addUser();
    }
}
  • 构造方法和setter方法都没有提供,仍然可以注入成功

5.2.2 方法上

  • UserServiceImpl
代码语言:javascript复制
package com.example.service.impl;

import com.example.dao.UserDao;
import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService {
    private UserDao userDao;

    @Autowired
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public void addUser() {
        userDao.addUser();
    }
}
  • UserController
代码语言:javascript复制
package com.example.controller;

import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller
public class UserController {
    private UserService userService;

    @Autowired
    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    public void addUser(){
        userService.addUser();
    }
}

5.2.3 构造方法上

  • UserServiceImpl
代码语言:javascript复制
package com.example.service.impl;

import com.example.dao.UserDao;
import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService {
    private UserDao userDao;

    @Autowired
    public UserServiceImpl(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public void addUser() {
        userDao.addUser();
    }
}
  • UserController
代码语言:javascript复制
package com.example.controller;

import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller
public class UserController {
    private UserService userService;

    @Autowired
    public UserController(UserService userService) {
        this.userService = userService;
    }

    public void addUser(){
        userService.addUser();
    }
}

5.2.4 形参上

  • UserServiceImpl
代码语言:javascript复制
package com.example.service.impl;

import com.example.dao.UserDao;
import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService {
    private UserDao userDao;

    public UserServiceImpl(@Autowired UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public void addUser() {
        userDao.addUser();
    }
}
  • UserController
代码语言:javascript复制
package com.example.controller;

import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller
public class UserController {
    private UserService userService;

    public UserController(@Autowired UserService userService) {
        this.userService = userService;
    }

    public void addUser(){
        userService.addUser();
    }
}

5.2.5 只有一个有参构造函数,无@Autowired

  • UserServiceImpl
代码语言:javascript复制
package com.example.service.impl;

import com.example.dao.UserDao;
import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService {
    private UserDao userDao;

    public UserServiceImpl(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public void addUser() {
        userDao.addUser();
    }
}
  • UserController
代码语言:javascript复制
package com.example.controller;

import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller
public class UserController {
    private UserService userService;

    public UserController(UserService userService) {
        this.userService = userService;
    }

    public void addUser(){
        userService.addUser();
    }
}
  • 当有参数的构造方法只有一个时,@Autowired注解可以省略。有多个构造方法时,测试报错

5.2.6 @Autowired注解和@Qualifier注解联合

  • 新增文件 UserRedisDaoImpl
代码语言:javascript复制
package com.example.dao.impl;

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

@Repository
public class UserRedisDaoImpl implements UserDao {
    @Override
    public void addUser() {
        System.out.println("UserRedisDaoImpl add user ...");
    }
}
  • 进行测试,报错=》有两个userDao,@Autowired注入的时候,根据类型注入,不知道用哪个
  • 解决:UserServiceImpl用@Autowired的同时,用@Qualifier注解指定bean的名字
代码语言:javascript复制
package com.example.service.impl;

import com.example.dao.UserDao;
import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    @Qualifier("userDaoImpl") // 指定bean的名字
    private UserDao userDao;

    @Override
    public void addUser() {
        userDao.addUser();
    }
}
  • 再次测试,通过

5.2.7 总结

  • @Autowired注解可以出现在:属性上、构造方法上、构造方法的参数上、setter方法上。
  • 当带参数的构造方法只有一个,@Autowired注解可以省略。
  • @Autowired注解默认根据类型注入。如果要根据名称注入的话,需要配合@Qualifier注解一起使用。

5.3 @Resource注入

5.3.1 @Resource注解和@Autowired注解的区别

  • @Resource注解是JDK扩展包中的,也就是说属于JDK的一部分。所以该注解是标准注解,更加具有通用性。(JSR-250标准中制定的注解类型。JSR是Java规范提案。)
  • @Autowired注解是Spring框架自己的。
  • @Resource注解默认根据名称装配byName,未指定name时,使用属性名作为name。通过name找不到的话会自动启动通过类型byType装配。
  • @Autowired注解默认根据类型装配byType,如果想根据名称装配,需要配合@Qualifier注解一起用。
  • @Resource注解用在属性上、setter方法上。
  • @Autowired注解用在属性上、setter方法上、构造方法上、构造方法参数上。

5.3.2 引入依赖

  • @Resource注解属于JDK扩展包,所以不在JDK当中,需要额外引入以下依赖
  • JDK8不需要额外引入依赖
  • 高于JDK11或低于JDK8需要引入以下依赖
代码语言:javascript复制
<dependency>
    <groupId>jakarta.annotation</groupId>
    <artifactId>jakarta.annotation-api</artifactId>
    <version>2.1.1</version>
</dependency>

5.3.3 @Resource声明

代码语言:javascript复制
@Target({TYPE, FIELD, METHOD})
@Retention(RUNTIME)
public @interface Resource {
    String name() default "";
    String lookup() default "";
    Class<?> type() default java.lang.Object.class;
    enum AuthenticationType {
            CONTAINER,
            APPLICATION
    }
    AuthenticationType authenticationType() default AuthenticationType.CONTAINER;
    boolean shareable() default true;
    String mappedName() default "";
    String description() default "";
}

5.3.4 实现

  • UserDao
代码语言:javascript复制
package com.example.dao;

public interface UserDao {
    void out();
}
  • UserDaoImpl
代码语言:javascript复制
package com.example.dao.impl;

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

@Repository(value="myUserDao")
public class UserDaoImpl implements UserDao {
    @Override
    public void out(){
        System.out.println("user dao....");
    }
}
  • UserService
代码语言:javascript复制
package com.example.service;

public interface UserService {
    void out();
}
  • UserServiceImpl
代码语言:javascript复制
package com.example.service.impl;

import com.example.dao.UserDao;
import com.example.service.UserService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Service
public class UserServiceImpl implements UserService {
    @Resource(name="myUserDao")  // 根据name注入
    private UserDao UserDao1;

    @Resource
    private UserDao myUserDao; // name未知注入,根据属性名注入

    @Resource
    private UserDao userDao; // 属性名找不到,根据类型注入
                             // 当UserDao有多个实现会报错

    @Override
    public void out() {
        UserDao1.out();
        myUserDao.out();
        userDao.out();
    }
}
  • UserController
代码语言:javascript复制
package com.example.controller;

import com.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller
public class UserController {
    @Autowired
    private UserService userService;
    public void out(){
        userService.out();
    }
}
  • bean.xml
代码语言:javascript复制
<?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 https://www.springframework.org/schema/context/spring-context.xsd">

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

</beans>
  • ResourceTest
代码语言:javascript复制
import com.example.controller.UserController;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class ResourceTest {
    @Test
    public void test(){
        ApplicationContext app = new ClassPathXmlApplicationContext("bean.xml");
        UserController bean = app.getBean(UserController.class);
        bean.out();
    }
}

5.4 全注解开发

  • 全注解开发就是不再使用spring配置文件了,写一个配置类来代替配置文
  • MainConfig
代码语言:javascript复制
package com.example.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
//@ComponentScan({"com.example.controller","com.example.service","com.example.dao"})
@ComponentScan("com.example")
//@Import(DataSourceConfiguration.class) // 引入一个分配置
@Import({DataSourceConfiguration.class}) // 引入多个分配置
public class MainConfig {

}
  • DataSourceConfiguration
代码语言:javascript复制
package com.example.config;

import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.PropertySource;

import javax.sql.DataSource;
import java.beans.PropertyVetoException;

// <context:property-placeholder location="classpath:jdbc.properties"/>
@PropertySource("classpath:jdbc.properties")
public class DataSourceConfiguration {
    @Value("${jdbc_driver}")
    private String driver;

    @Value("${jdbc_url}")
    private String url;
    @Value("${jdbc_username}")
    private String userName;
    @Value("${jdbc_password}")
    private String password;

    @Bean("dataSource") // Spring会将当前方法的返回值以指定名称存储到Spring容器中
    public DataSource f() throws PropertyVetoException {
        // TODO 手动创建c3p0数据源
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setDriverClass(driver);
        dataSource.setJdbcUrl(url);
        dataSource.setUser(userName);
        dataSource.setPassword(password);
        return dataSource;
    }
}

UserController

代码语言:javascript复制
package com.example.controller;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Repository;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

@Scope("prototype")
@Repository("myUserController")
public class UserController {
    private String name;

    public void out() {
        System.out.println("out running....");
    }

    @PostConstruct
    public void init(){
        System.out.println("init method....");
    }

    @PreDestroy
    public void destroy(){
        System.out.println("destroy method....");
    }
}
  • AllAutoTest
代码语言:javascript复制
import com.example.config.MainConfig;
import com.example.controller.UserController;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import javax.annotation.Resource;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {MainConfig.class})
public class AllAutoTest {
    @Autowired
    private UserController userController;

    @Test
    public void test(){
        userController.out();
        System.out.println(userController);
    }
}

5.5 Java反射

  • Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制。简单来说,反射机制指的是程序在运行时能够获取自身的信息。
  • 引入依赖:lombok不用写get、set、toString、构造函数
代码语言:javascript复制
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>
  • Car
代码语言:javascript复制
package com.example.dao;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

@AllArgsConstructor // 全参构造器
@NoArgsConstructor // 无参构造器
@ToString
@Data
public class Car {
    /**
     * 属性
     */
    private String name;
    private int age;
    private String color;

    /**
     * 私有方法
     */
    private void run() {
        System.out.println("run.....");
    }
}
  • CarReflectTest
代码语言:javascript复制
import com.example.dao.Car;
import org.junit.Test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;

public class CarReflectTest {
    /**
     * 1. 获取Class对象多种方式
     */
    @Test
    public void test01() throws Exception {
        // 1. 类名.class
        Class clazz1 = Car.class;
        System.out.println("clazz1: "   clazz1);

        // 2. 对象.getClass()
        Class clazz2 = new Car().getClass();
        System.out.println("clazz2: "   clazz2);

        // 3. Class.forName("全路径")
        Class clazz3 = Class.forName("com.example.dao.Car");
        System.out.println("clazz3: "   clazz3);

        // 4. 实例化
        Car car = (Car)clazz3.getConstructor().newInstance();
        System.out.println(car);
    }

    /**
     * 2. 获取构造方法
     * @throws Exception
     */
    @Test
    public void test02() throws Exception {
        Class clazz = Car.class;
        // 1. 获取所有构造
        // 1.1 getConstructors()获取所有public的构造方法
        Constructor[] constructors = clazz.getConstructors();
        System.out.println(Arrays.toString(constructors));

        // 1.2 getDeclaredConstructors()获取所有的构造方法public  private
        Constructor[] constructors2 = clazz.getDeclaredConstructors();
        for (Constructor c:constructors2) {
            System.out.println("方法名称:" c.getName() " 参数个数:" c.getParameterCount());
        }

        // 2. 指定有参数构造创建对象
        // 2.1 构造public
        Constructor c1 = clazz.getConstructor(String.class, int.class, String.class);
        Car car1 = (Car)c1.newInstance("夏利", 10, "红色");
        System.out.println(car1);

        // 2.2 构造private
        Constructor c2 = clazz.getDeclaredConstructor(String.class, int.class, String.class);
        c2.setAccessible(true);
        Car car2 = (Car)c2.newInstance("捷达", 15, "白色");
        System.out.println(car2);
    }

    /**
     * 3. 获取属性
     */
    @Test
    public void test03() throws Exception {
        Class clazz = Car.class;
        Car car = (Car)clazz.getDeclaredConstructor().newInstance();

        // 获取所有public属性
        Field[] fields = clazz.getFields();
        System.out.println(Arrays.toString(fields));

        // 获取所有属性(包含私有属性)
        Field[] fields2 = clazz.getDeclaredFields();
        for (Field field:fields2) {
            if(field.getName().equals("name")) {
                // 设置允许访问
                field.setAccessible(true); // 不设置,会报错
                field.set(car,"五菱宏光");
                System.out.println(car);
            }
            System.out.println(field.getName());
        }
    }

    /**
     * 4. 获取方法
     * @throws Exception
     */
    @Test
    public void test04() throws Exception {
        Car car = new Car("奔驰",10,"黑色");
        Class clazz = car.getClass();

        // 1. public方法
        Method[] methods = clazz.getMethods();
        for (Method m1:methods) {
            System.out.println("Car Method: "   m1.getName());
            // 执行方法 toString
            if(m1.getName().equals("toString")) {
                String invoke = (String)m1.invoke(car);
                System.out.println("toString执行了:"  invoke);
            }
        }

        // 2. private方法
        Method[] methodsAll = clazz.getDeclaredMethods();
        for (Method m:methodsAll) {
            // 执行方法 run
            if(m.getName().equals("run")) {
                m.setAccessible(true);
                m.invoke(car);
            }
        }
    }
}

5.6 实现Spring的IoC和DI

  • MyDI注解
代码语言:javascript复制
package com.example.spring.core.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.FIELD}) // Method declaration
@Retention(RetentionPolicy.RUNTIME)
public @interface MyDI {
}
  • MyBean注解
代码语言:javascript复制
package com.example.spring.core.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE) // ElementType.TYPE: Class, interface (including annotation type), or enum declaration // 能修饰类、接口、注解、枚举
@Retention(RetentionPolicy.RUNTIME)
public @interface MyBean {
}
  • ApplicationContext接口
代码语言:javascript复制
package com.example.spring.core;

public interface ApplicationContext {
    Object getBean(Class clazz);
}
  • AnnotationApplicationContext
代码语言:javascript复制
package com.example.spring.core.impl;

import java.io.File;
import java.lang.reflect.Field;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

import com.example.spring.core.ApplicationContext;
import com.example.spring.core.annotation.MyBean;
import com.example.spring.core.annotation.MyDI;

public class AnnotationApplicationContext implements ApplicationContext {
    //存储bean的容器
    private HashMap<Class, Object> beanFactory = new HashMap<>();
    private static String rootPath;

    @Override
    public Object getBean(Class clazz) {
        return beanFactory.get(clazz);
    }

    /**
     * 根据包扫描加载bean
     * @param basePackage
     */
    public AnnotationApplicationContext(String basePackage) {
        try {
            String packageDirName = basePackage.replaceAll("\.", "\\");
            Enumeration<URL> dirs =Thread.currentThread().getContextClassLoader().getResources(packageDirName);
            while (dirs.hasMoreElements()) {
                URL url = dirs.nextElement();
                String filePath = URLDecoder.decode(url.getFile(),"utf-8");
                rootPath = filePath.substring(0, filePath.length()-packageDirName.length());
                loadBean(new File(filePath));
            }
            System.out.println(beanFactory);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        //依赖注入
        loadDi();
    }

    private  void loadBean(File fileParent) {
        if (fileParent.isDirectory()) {
            File[] childrenFiles = fileParent.listFiles();
            if(childrenFiles == null || childrenFiles.length == 0){
                return;
            }
            for (File child : childrenFiles) {
                if (child.isDirectory()) {
                    //如果是个文件夹就继续调用该方法,使用了递归
                    loadBean(child);
                } else {
                    //通过文件路径转变成全类名,第一步把绝对路径部分去掉
                    String pathWithClass = child.getAbsolutePath().substring(rootPath.length() - 1);
                    //选中class文件
                    if (pathWithClass.contains(".class")) {
                        //    com.xinzhi.dao.UserDao
                        //去掉.class后缀,并且把  替换成 .
                        String fullName = pathWithClass.replaceAll("\\", ".").replace(".class", "");
                        try {
                            Class<?> aClass = Class.forName(fullName);
                            //把非接口的类实例化放在map中
                            if(!aClass.isInterface()){
                                MyBean annotation = aClass.getAnnotation(MyBean.class);
                                if(annotation != null){
                                    Object instance = aClass.newInstance();
                                    //判断一下有没有接口
                                    if(aClass.getInterfaces().length > 0) {
                                        //如果有接口把接口的class当成key,实例对象当成value
                                        System.out.println("正在加载【"  aClass.getInterfaces()[0]  "】,实例对象是:"   instance.getClass().getName());
                                        beanFactory.put(aClass.getInterfaces()[0], instance);
                                    }else{
                                        //如果有接口把自己的class当成key,实例对象当成value
                                        System.out.println("正在加载【"  aClass.getName()  "】,实例对象是:"   instance.getClass().getName());
                                        beanFactory.put(aClass, instance);
                                    }
                                }
                            }
                        } catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }

    private void loadDi() {
        for(Map.Entry<Class,Object> entry : beanFactory.entrySet()){
            //就是咱们放在容器的对象
            Object obj = entry.getValue();
            Class<?> aClass = obj.getClass();
            Field[] declaredFields = aClass.getDeclaredFields();
            for (Field field : declaredFields){
                MyDI annotation = field.getAnnotation(MyDI.class);
                if( annotation != null ){
                    field.setAccessible(true);
                    try {
                        System.out.println("正在给【" obj.getClass().getName() "】属性【"   field.getName()   "】注入值【"  beanFactory.get(field.getType()).getClass().getName()  "】");
                        field.set(obj,beanFactory.get(field.getType()));
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}
  • Brand
代码语言:javascript复制
package com.example.dao;

import com.example.spring.core.annotation.MyBean;
import com.example.spring.core.annotation.MyDI;
import lombok.Data;
import lombok.ToString;

@MyBean
@Data
@ToString
public class Brand {
    private String name;
}
  • Car
代码语言:javascript复制
package com.example.dao;


import com.example.spring.core.annotation.MyBean;
import com.example.spring.core.annotation.MyDI;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

@AllArgsConstructor // 全参构造器
@NoArgsConstructor // 无参构造器
@ToString
@Data
@MyBean
public class Car {
    /**
     * 属性
     */
    private String name;
    private int age;
    private String color;

    @MyDI
    private Brand brand;

    /**
     * 私有方法
     */
    private void run() {
        System.out.println("run.....");
    }

}
  • IoCTest
代码语言:javascript复制
import com.example.dao.Car;
import com.example.spring.core.ApplicationContext;
import com.example.spring.core.impl.AnnotationApplicationContext;
import org.junit.Test;

public class IoCTest {
    @Test
    public void test(){
        ApplicationContext app = new AnnotationApplicationContext("com.example");
        Car car = (Car) app.getBean(Car.class);
        System.out.println(car.getBrand());
    }
}

0 人点赞