国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Spring IOC基于XML和注解管理Bean(二)

這篇具有很好參考價值的文章主要介紹了Spring IOC基于XML和注解管理Bean(二)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

Spring IOC基于XML和注解管理Bean(一)

2.9、實驗八:p命名空間

引入p命名空間

<?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:util="http://www.springframework.org/schema/util"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/util
       http://www.springframework.org/schema/util/spring-util.xsd
       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

引入p命名空間后,可以通過以下方式為bean的各個屬性賦值

<bean id="studentSix" class="org.example.bean.Student"
    p:id="1006" p:name="小明" p:clazz-ref="clazzOne" p:teacherMap-ref="teacherMap"></bean>

2.10、實驗九:引入外部屬性文件

①加入依賴

 <!-- MySQL驅動 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.30</version>
</dependency>

<!-- 數據源 -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.15</version>
</dependency>

②創(chuàng)建外部屬性文件

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-EEZ1sTcC-1686469380998)(img/2023-05-25-21-43-05.png)]

jdbc.user=root
jdbc.password=123456
jdbc.url=jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC
jdbc.driver=com.mysql.cj.jdbc.Driver

③引入屬性文件

引入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:property-placeholder location="classpath:jdbc.properties"/>

注意:在使用 <context:property-placeholder> 元素加載外包配置文件功能前,首先需要在 XML 配置的一級標簽 <beans> 中添加 context 相關的約束。

④配置bean

<bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
    <property name="url" value="${jdbc.url}"/>
    <property name="driverClassName" value="${jdbc.driver}"/>
    <property name="username" value="${jdbc.user}"/>
    <property name="password" value="${jdbc.password}"/>
</bean>

⑤測試

@Test
public void testDataSource() throws SQLException {
    ApplicationContext ac = new ClassPathXmlApplicationContext("spring-datasource.xml");
    DataSource dataSource = ac.getBean(DataSource.class);
    Connection connection = dataSource.getConnection();
    System.out.println(connection);
}

2.11、實驗十:bean的作用域

①概念

在Spring中可以通過配置bean標簽的scope屬性來指定bean的作用域范圍,各取值含義參加下表:

取值 含義 創(chuàng)建對象的時機
singleton(默認) 在IOC容器中,這個bean的對象始終為單實例 IOC容器初始化時
prototype 這個bean在IOC容器中有多個實例 獲取bean時

如果是在WebApplicationContext環(huán)境下還會有另外幾個作用域(但不常用):

取值 含義
request 在一個請求范圍內有效
session 在一個會話范圍內有效

②創(chuàng)建類User

package org.example.bean;
public class User {

    private Integer id;

    private String username;

    private String password;

    private Integer age;

    public User() {
    }

    public User(Integer id, String username, String password, Integer age) {
        this.id = id;
        this.username = username;
        this.password = password;
        this.age = age;
    }

    public Integer getId() {
        return id;
    }

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

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", age=" + age +
                '}';
    }
}

③配置bean

<!-- scope屬性:取值singleton(默認值),bean在IOC容器中只有一個實例,IOC容器初始化時創(chuàng)建對象 -->
<!-- scope屬性:取值prototype,bean在IOC容器中可以有多個實例,getBean()時創(chuàng)建對象 -->
<bean class="org.example.bean.User" scope="prototype"></bean>

④測試

@Test
public void testBeanScope(){
    ApplicationContext ac = new ClassPathXmlApplicationContext("spring-scope.xml");
    User user1 = ac.getBean(User.class);
    User user2 = ac.getBean(User.class);
    System.out.println(user1==user2);
}

2.12、實驗十一:bean生命周期

①具體的生命周期過程

  • 1、bean對象創(chuàng)建(調用無參構造器)

  • 2、給bean對象設置屬性

  • 3、bean的后置處理器(初始化之前)

  • 4、bean對象初始化(需在配置bean時指定初始化方法)

  • 5、bean的后置處理器(初始化之后)

  • 6、bean對象就緒可以使用

  • 7、bean對象銷毀(需在配置bean時指定銷毀方法)

  • 8、IOC容器關閉

②修改類User

public class User {

    private Integer id;

    private String username;

    private String password;

    private Integer age;

    public User() {
        System.out.println("生命周期:1、創(chuàng)建對象");
    }

    public User(Integer id, String username, String password, Integer age) {
        this.id = id;
        this.username = username;
        this.password = password;
        this.age = age;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        System.out.println("生命周期:2、依賴注入");
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public void initMethod(){
        System.out.println("生命周期:3、初始化");
    }

    public void destroyMethod(){
        System.out.println("生命周期:5、銷毀");
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", age=" + age +
                '}';
    }
}

注意其中的initMethod()destroyMethod(),可以通過配置bean指定為初始化和銷毀的方法

③配置bean

<!-- 使用init-method屬性指定初始化方法 -->
<!-- 使用destroy-method屬性指定銷毀方法 -->
<bean class="org.example.bean.User" scope="prototype" init-method="initMethod" destroy-method="destroyMethod">
    <property name="id" value="1001"></property>
    <property name="username" value="admin"></property>
    <property name="password" value="123456"></property>
    <property name="age" value="23"></property>
</bean>

④測試

@Test
public void testLife(){
    ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("spring-lifecycle.xml");
    User bean = ac.getBean(User.class);
    System.out.println("生命周期:4、通過IOC容器獲取bean并使用");
    ac.close();
}

⑤bean的后置處理器

bean的后置處理器會在生命周期的初始化前后添加額外的操作,需要實現BeanPostProcessor接口,且配置到IOC容器中,需要注意的是,bean后置處理器不是單獨針對某一個bean生效,而是針對IOC容器中所有bean都會執(zhí)行

創(chuàng)建bean的后置處理器:

package org.example.process;
    
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

public class MyBeanProcessor implements BeanPostProcessor {
    
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("☆☆☆" + beanName + " = " + bean);
        return bean;
    }
    
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("★★★" + beanName + " = " + bean);
        return bean;
    }
}

在IOC容器中配置后置處理器:

<!-- bean的后置處理器要放入IOC容器才能生效 -->
<bean id="myBeanProcessor" class="org.example.process.MyBeanProcessor"/>

2.13、實驗十二:FactoryBean

①簡介

FactoryBean是Spring提供的一種整合第三方框架的常用機制。和普通的bean不同,配置一個FactoryBean類型的bean,在獲取bean的時候得到的并不是class屬性中配置的這個類的對象,而是getObject()方法的返回值。通過這種機制,Spring可以幫我們把復雜組件創(chuàng)建的詳細過程和繁瑣細節(jié)都屏蔽起來,只把最簡潔的使用界面展示給我們。

整合Mybatis時,Spring就是通過FactoryBean機制來幫我們創(chuàng)建SqlSessionFactory對象的。

/*
 * Copyright 2002-2020 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.springframework.beans.factory;

import org.springframework.lang.Nullable;

/**
 * Interface to be implemented by objects used within a {@link BeanFactory} which
 * are themselves factories for individual objects. If a bean implements this
 * interface, it is used as a factory for an object to expose, not directly as a
 * bean instance that will be exposed itself.
 *
 * <p><b>NB: A bean that implements this interface cannot be used as a normal bean.</b>
 * A FactoryBean is defined in a bean style, but the object exposed for bean
 * references ({@link #getObject()}) is always the object that it creates.
 *
 * <p>FactoryBeans can support singletons and prototypes, and can either create
 * objects lazily on demand or eagerly on startup. The {@link SmartFactoryBean}
 * interface allows for exposing more fine-grained behavioral metadata.
 *
 * <p>This interface is heavily used within the framework itself, for example for
 * the AOP {@link org.springframework.aop.framework.ProxyFactoryBean} or the
 * {@link org.springframework.jndi.JndiObjectFactoryBean}. It can be used for
 * custom components as well; however, this is only common for infrastructure code.
 *
 * <p><b>{@code FactoryBean} is a programmatic contract. Implementations are not
 * supposed to rely on annotation-driven injection or other reflective facilities.</b>
 * {@link #getObjectType()} {@link #getObject()} invocations may arrive early in the
 * bootstrap process, even ahead of any post-processor setup. If you need access to
 * other beans, implement {@link BeanFactoryAware} and obtain them programmatically.
 *
 * <p><b>The container is only responsible for managing the lifecycle of the FactoryBean
 * instance, not the lifecycle of the objects created by the FactoryBean.</b> Therefore,
 * a destroy method on an exposed bean object (such as {@link java.io.Closeable#close()}
 * will <i>not</i> be called automatically. Instead, a FactoryBean should implement
 * {@link DisposableBean} and delegate any such close call to the underlying object.
 *
 * <p>Finally, FactoryBean objects participate in the containing BeanFactory's
 * synchronization of bean creation. There is usually no need for internal
 * synchronization other than for purposes of lazy initialization within the
 * FactoryBean itself (or the like).
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @since 08.03.2003
 * @param <T> the bean type
 * @see org.springframework.beans.factory.BeanFactory
 * @see org.springframework.aop.framework.ProxyFactoryBean
 * @see org.springframework.jndi.JndiObjectFactoryBean
 */
public interface FactoryBean<T> {

    /**
     * The name of an attribute that can be
     * {@link org.springframework.core.AttributeAccessor#setAttribute set} on a
     * {@link org.springframework.beans.factory.config.BeanDefinition} so that
     * factory beans can signal their object type when it can't be deduced from
     * the factory bean class.
     * @since 5.2
     */
    String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";

    /**
     * Return an instance (possibly shared or independent) of the object
     * managed by this factory.
     * <p>As with a {@link BeanFactory}, this allows support for both the
     * Singleton and Prototype design pattern.
     * <p>If this FactoryBean is not fully initialized yet at the time of
     * the call (for example because it is involved in a circular reference),
     * throw a corresponding {@link FactoryBeanNotInitializedException}.
     * <p>As of Spring 2.0, FactoryBeans are allowed to return {@code null}
     * objects. The factory will consider this as normal value to be used; it
     * will not throw a FactoryBeanNotInitializedException in this case anymore.
     * FactoryBean implementations are encouraged to throw
     * FactoryBeanNotInitializedException themselves now, as appropriate.
     * @return an instance of the bean (can be {@code null})
     * @throws Exception in case of creation errors
     * @see FactoryBeanNotInitializedException
     */
    @Nullable
    T getObject() throws Exception;

    /**
     * Return the type of object that this FactoryBean creates,
     * or {@code null} if not known in advance.
     * <p>This allows one to check for specific types of beans without
     * instantiating objects, for example on autowiring.
     * <p>In the case of implementations that are creating a singleton object,
     * this method should try to avoid singleton creation as far as possible;
     * it should rather estimate the type in advance.
     * For prototypes, returning a meaningful type here is advisable too.
     * <p>This method can be called <i>before</i> this FactoryBean has
     * been fully initialized. It must not rely on state created during
     * initialization; of course, it can still use such state if available.
     * <p><b>NOTE:</b> Autowiring will simply ignore FactoryBeans that return
     * {@code null} here. Therefore it is highly recommended to implement
     * this method properly, using the current state of the FactoryBean.
     * @return the type of object that this FactoryBean creates,
     * or {@code null} if not known at the time of the call
     * @see ListableBeanFactory#getBeansOfType
     */
    @Nullable
    Class<?> getObjectType();

    /**
     * Is the object managed by this factory a singleton? That is,
     * will {@link #getObject()} always return the same object
     * (a reference that can be cached)?
     * <p><b>NOTE:</b> If a FactoryBean indicates to hold a singleton object,
     * the object returned from {@code getObject()} might get cached
     * by the owning BeanFactory. Hence, do not return {@code true}
     * unless the FactoryBean always exposes the same reference.
     * <p>The singleton status of the FactoryBean itself will generally
     * be provided by the owning BeanFactory; usually, it has to be
     * defined as singleton there.
     * <p><b>NOTE:</b> This method returning {@code false} does not
     * necessarily indicate that returned objects are independent instances.
     * An implementation of the extended {@link SmartFactoryBean} interface
     * may explicitly indicate independent instances through its
     * {@link SmartFactoryBean#isPrototype()} method. Plain {@link FactoryBean}
     * implementations which do not implement this extended interface are
     * simply assumed to always return independent instances if the
     * {@code isSingleton()} implementation returns {@code false}.
     * <p>The default implementation returns {@code true}, since a
     * {@code FactoryBean} typically manages a singleton instance.
     * @return whether the exposed object is a singleton
     * @see #getObject()
     * @see SmartFactoryBean#isPrototype()
     */
    default boolean isSingleton() {
        return true;
    }
}

②創(chuàng)建類UserFactoryBean

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

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

③配置bean

<bean id="user" class="org.example.bean.UserFactoryBean"></bean>

④測試

@Test
public void testUserFactoryBean(){
    //獲取IOC容器
    ApplicationContext ac = new ClassPathXmlApplicationContext("spring-factorybean.xml");
    User user = (User) ac.getBean("user");
    System.out.println(user);
}

2.14、實驗十三:基于xml自動裝配

自動裝配:

根據指定的策略,在IOC容器中匹配某一個bean,自動為指定的bean中所依賴的類類型或接口類型屬性賦值

①場景模擬

創(chuàng)建類UserController

package org.example.autowire.controller;
public class UserController {

    private UserService userService;

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

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

}

創(chuàng)建接口UserService

package org.example.autowire.service;
public interface UserService {

    void saveUser();

}

創(chuàng)建類UserServiceImpl實現接口UserService

package org.example.autowire.service.impl;
public class UserServiceImpl implements UserService {

    private UserDao userDao;

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

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

}

創(chuàng)建接口UserDao

package org.example.autowire.dao;
public interface UserDao {

    void saveUser();

}

創(chuàng)建類UserDaoImpl實現接口UserDao

package org.example.autowire.dao.impl;
public class UserDaoImpl implements UserDao {

    @Override
    public void saveUser() {
        System.out.println("保存成功");
    }

}

②配置bean

使用bean標簽的autowire屬性設置自動裝配效果

自動裝配方式:byType

byType:根據類型匹配IOC容器中的某個兼容類型的bean,為屬性自動賦值

若在IOC中,沒有任何一個兼容類型的bean能夠為屬性賦值,則該屬性不裝配,即值為默認值null

若在IOC中,有多個兼容類型的bean能夠為屬性賦值,則拋出異常NoUniqueBeanDefinitionException

<bean id="userController" class="org.example.autowire.controller.UserController" autowire="byType"></bean>

<bean id="userService" class="org.example.autowire.service.impl.UserServiceImpl" autowire="byType"></bean>

<bean id="userDao" class="org.example.autowire.dao.impl.UserDaoImpl"></bean>

自動裝配方式:byName

byName:將自動裝配的屬性的屬性名,作為bean的id在IOC容器中匹配相對應的bean進行賦值

<bean id="userController" class="org.example.autowire.controller.UserController" autowire="byName"></bean>

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

<bean id="userDao" class="org.example.autowire.dao.impl.UserDaoImpl"></bean>
<bean id="userDaoImpl" class="org.example.autowire.dao.impl.UserDaoImpl"></bean>

③測試

@Test
public void testAutoWireByXML(){
    ApplicationContext ac = new ClassPathXmlApplicationContext("autowire-xml.xml");
    UserController userController = ac.getBean(UserController.class);
    userController.saveUser();
}

3、基于注解管理Bean

從 Java 5 開始,Java 增加了對注解(Annotation)的支持,它是代碼中的一種特殊標記,可以在編譯、類加載和運行時被讀取,執(zhí)行相應的處理。開發(fā)人員可以通過注解在不改變原有代碼和邏輯的情況下,在源代碼中嵌入補充信息。

Spring 從 2.5 版本開始提供了對注解技術的全面支持,我們可以使用注解來實現自動裝配,簡化 Spring 的 XML 配置。

Spring 通過注解實現自動裝配的步驟如下:

  1. 引入依賴
  2. 開啟組件掃描
  3. 使用注解定義 Bean
  4. 依賴注入

3.1、搭建子模塊spring6-ioc-annotation

①搭建模塊

搭建方式如:spring6-ioc-xml

②引入配置文件

引入spring-ioc-xml模塊日志log4j2.xml

③添加依賴

<dependencies>
    <!--spring context依賴-->
    <!--當你引入Spring Context依賴之后,表示將Spring的基礎依賴引入了-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>6.0.3</version>
    </dependency>

    <!--junit5測試-->
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-api</artifactId>
    </dependency>

    <!--log4j2的依賴-->
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>2.19.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-slf4j2-impl</artifactId>
        <version>2.19.0</version>
    </dependency>
</dependencies>

3.2、開啟組件掃描

Spring 默認不使用注解裝配 Bean,因此我們需要在 Spring 的 XML 配置中,通過 <context:component-scan> 元素開啟 Spring Beans的自動掃描功能。開啟此功能后,Spring 會自動從掃描指定的包(base-package 屬性設置)及其子包下的所有類,如果類上使用了 @Component 注解,就將該類裝配到容器中。

<?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-3.0.xsd
    http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context.xsd">
    <!--開啟組件掃描功能-->
    <context:component-scan base-package="org.example"></context:component-scan>
</beans>

注意:在使用 <context:component-scan> 元素開啟自動掃描功能前,首先需要在 XML 配置的一級標簽 <beans> 中添加 context 相關的約束。

情況一:最基本的掃描方式

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

情況二:指定要排除的組件

<context:component-scan base-package="org.example">
    <!-- context:exclude-filter標簽:指定排除規(guī)則 -->
    <!-- 
 		type:設置排除或包含的依據
		type="annotation",根據注解排除,expression中設置要排除的注解的全類名
		type="assignable",根據類型排除,expression中設置要排除的類型的全類名
	-->
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
        <!--<context:exclude-filter type="assignable" expression="org.example.controller.UserController"/>-->
</context:component-scan>

情況三:僅掃描指定組件

<context:component-scan base-package="org.example" use-default-filters="false">
    <!-- context:include-filter標簽:指定在原有掃描規(guī)則的基礎上追加的規(guī)則 -->
    <!-- use-default-filters屬性:取值false表示關閉默認掃描規(guī)則 -->
    <!-- 此時必須設置use-default-filters="false",因為默認規(guī)則即掃描指定包下所有類 -->
    <!-- 
 		type:設置排除或包含的依據
		type="annotation",根據注解排除,expression中設置要排除的注解的全類名
		type="assignable",根據類型排除,expression中設置要排除的類型的全類名
	-->
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
	<!--<context:include-filter type="assignable" expression="org.example.controller.UserController"/>-->
</context:component-scan>

3.3、使用注解定義 Bean

Spring 提供了以下多個注解,這些注解可以直接標注在 Java 類上,將它們定義成 Spring Bean。

注解 說明
@Component 該注解用于描述 Spring 中的 Bean,它是一個泛化的概念,僅僅表示容器中的一個組件(Bean),并且可以作用在應用的任何層次,例如 Service 層、Dao 層等。 使用時只需將該注解標注在相應類上即可。
@Repository 該注解用于將數據訪問層(Dao 層)的類標識為 Spring 中的 Bean,其功能與 @Component 相同。
@Service 該注解通常作用在業(yè)務層(Service 層),用于將業(yè)務層的類標識為 Spring 中的 Bean,其功能與 @Component 相同。
@Controller 該注解通常作用在控制層(如SpringMVC 的 Controller),用于將控制層的類標識為 Spring 中的 Bean,其功能與 @Component 相同。

3.4、實驗一:@Autowired注入

單獨使用@Autowired注解,默認根據類型裝配?!灸J是byType

查看源碼:

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存在或者不存在都沒關系,存在的話就注入,不存在的話,也不報錯。

①場景一:屬性注入

創(chuàng)建UserDao接口

package org.example.dao;

public interface UserDao {

    public void print();
}

創(chuàng)建UserDaoImpl實現

package org.example.dao.impl;

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

@Repository
public class UserDaoImpl implements UserDao {

    @Override
    public void print() {
        System.out.println("Dao層執(zhí)行結束");
    }
}

創(chuàng)建UserService接口

package org.example.spring6.service;

public interface UserService {

    public void out();
}

創(chuàng)建UserServiceImpl實現類

package org.example.spring6.service.impl;

import org.example.spring6.dao.UserDao;
import org.example.spring6.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 out() {
        userDao.print();
        System.out.println("Service層執(zhí)行結束");
    }
}

創(chuàng)建UserController類

package org.exampleu.spring6.controller;

import org.example.spring6.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();
        System.out.println("Controller層執(zhí)行結束。");
    }

}

測試一

package org.example.spring6.bean;

import org.example.spring6.controller.UserController;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class UserTest {

    private Logger logger = LoggerFactory.getLogger(UserTest.class);

    @Test
    public void testAnnotation(){
        ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
        UserController userController = context.getBean("userController", UserController.class);
        userController.out();
        logger.info("執(zhí)行成功");
    }


}

以上構造方法和setter方法都沒有提供,經過測試,仍然可以注入成功。

②場景二:set注入

修改UserServiceImpl類

package org.example.service.impl;

import org.example.dao.UserDao;
import org.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 out() {
        userDao.print();
        System.out.println("Service層執(zhí)行結束");
    }
}

修改UserController類

package org.example.controller;

import org.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 out() {
        userService.out();
        System.out.println("Controller層執(zhí)行結束。");
    }

}

測試:成功調用

③場景三:構造方法注入

修改UserServiceImpl類

package org.example.service.impl;

import org.example.dao.UserDao;
import org.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 out() {
        userDao.print();
        System.out.println("Service層執(zhí)行結束");
    }
}

修改UserController類

package org.example.controller;

import org.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 out() {
        userService.out();
        System.out.println("Controller層執(zhí)行結束。");
    }

}

測試:成功調用

注:在 Spring4.x 中增加了新的特性:如果類只提供了一個帶參數的構造方法,則不需要對對其內部的屬性寫 @Autowired 注解,Spring 會自動為你注入屬性。(請看場景五)

④場景四:形參上注入

修改UserServiceImpl類

package org.example.service.impl;

import org.example.spring6.dao.UserDao;
import org.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 out() {
        userDao.print();
        System.out.println("Service層執(zhí)行結束");
    }
}

修改UserController類

package org.example.controller;

import org.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 out() {
        userService.out();
        System.out.println("Controller層執(zhí)行結束。");
    }

}

測試:成功調用

⑤場景五:只有一個構造函數,無注解

修改UserServiceImpl類

package org.example.service.impl;

import org.example.dao.UserDao;
import org.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
    private UserDao userDao;

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

    @Override
    public void out() {
        userDao.print();
        System.out.println("Service層執(zhí)行結束");
    }
}

測試通過

當有參數的構造方法只有一個時,@Autowired注解可以省略。

說明:有多個構造方法時呢?大家可以測試(再添加一個無參構造函數),測試報錯

⑥場景六:@Autowired注解和@Qualifier注解聯合

添加dao層實現

package org.example.dao.impl;

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

@Repository
public class UserDaoRedisImpl implements UserDao {

    @Override
    public void print() {
        System.out.println("Redis Dao層執(zhí)行結束");
    }
}

測試:測試異常

錯誤信息中說:不能裝配,UserDao這個Bean的數量等于2

怎么解決這個問題呢?當然要byName,根據名稱進行裝配了。

修改UserServiceImpl類

package org.example.service.impl;

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

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    @Qualifier("userDaoImpl") // 指定bean的名字
    private UserDao userDao;

    @Override
    public void out() {
        userDao.print();
        System.out.println("Service層執(zhí)行結束");
    }
}

總結

  • @Autowired注解可以出現在:屬性上、構造方法上、構造方法的參數上、setter方法上。
  • 當帶參數的構造方法只有一個,@Autowired注解可以省略。()
  • @Autowired注解默認根據類型注入。如果要根據名稱注入的話,需要配合@Qualifier注解一起使用。

3.5、實驗二:@Resource注入

@Resource注解也可以完成屬性注入。那它和@Autowired注解有什么區(qū)別?

  • @Resource注解是JDK擴展包中的,也就是說屬于JDK的一部分。所以該注解是標準注解,更加具有通用性。(JSR-250標準中制定的注解類型。JSR是Java規(guī)范提案。)
  • @Autowired注解是Spring框架自己的。
  • @Resource注解默認根據名稱裝配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>

源碼:

package jakarta.annotation;

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

@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Resources.class)
public @interface Resource {
    String name() default "";

    String lookup() default "";

    Class<?> type() default Object.class;

    Resource.AuthenticationType authenticationType() default Resource.AuthenticationType.CONTAINER;

    boolean shareable() default true;

    String mappedName() default "";

    String description() default "";

    public static enum AuthenticationType {
        CONTAINER,
        APPLICATION;

        private AuthenticationType() {
        }
    }
}
①場景一:根據name注入

修改UserDaoImpl類

package org.example.dao.impl;

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

@Repository("myUserDao")
public class UserDaoImpl implements UserDao {

    @Override
    public void print() {
        System.out.println("Dao層執(zhí)行結束");
    }
}

修改UserServiceImpl類

package org.example.service.impl;

import org.example.dao.UserDao;
import org.example.service.UserService;
import jakarta.annotation.Resource;
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 {

    @Resource(name = "myUserDao")
    private UserDao myUserDao;

    @Override
    public void out() {
        myUserDao.print();
        System.out.println("Service層執(zhí)行結束");
    }
}

測試通過

②場景二:name未知注入

修改UserDaoImpl類

package org.example.dao.impl;

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

@Repository("myUserDao")
public class UserDaoImpl implements UserDao {

    @Override
    public void print() {
        System.out.println("Dao層執(zhí)行結束");
    }
}

修改UserServiceImpl類

package org.example.service.impl;

import org.example.dao.UserDao;
import org.example.service.UserService;
import jakarta.annotation.Resource;
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 {

    @Resource
    private UserDao myUserDao;

    @Override
    public void out() {
        myUserDao.print();
        System.out.println("Service層執(zhí)行結束");
    }
}

測試通過

@Resource注解使用時沒有指定name的時候,還是根據name進行查找,這個name是 屬性名 。

③場景三 其他情況

修改UserServiceImpl類,userDao1屬性名不存在

package org.example.service.impl;

import org.example.dao.UserDao;
import org.example.service.UserService;
import jakarta.annotation.Resource;
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 {

    @Resource
    private UserDao userDao1;

    @Override
    public void out() {
        userDao1.print();
        System.out.println("Service層執(zhí)行結束");
    }
}

測試異常

根據異常信息得知:顯然當通過name找不到的時候,自然會啟動byType進行注入,以上的錯誤是因為UserDao接口下有兩個實現類導致的。所以根據類型注入就會報錯。

@Resource的set注入可以自行測試

總結:

@Resource注解:默認byName注入,沒有指定name時把屬性名當做name,根據name找不到時,才會byType注入。byType注入時,某種類型的Bean只能有一個

3.6、Spring全注解開發(fā)

全注解開發(fā)就是不再使用spring配置文件了,寫一個配置類來代替配置文件。

package org.example.config;

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

@Configuration
//@ComponentScan({"org.example.controller", "org.example.service","org.example.dao"})
@ComponentScan("org.example")
public class Spring6Config {
}

測試類文章來源地址http://www.zghlxwxcb.cn/news/detail-483748.html

@Test
public void testAllAnnotation(){
    ApplicationContext context = new AnnotationConfigApplicationContext(Spring6Config.class);
    UserController userController = context.getBean("userController", UserController.class);
    userController.out();
    logger.info("執(zhí)行成功");
}

到了這里,關于Spring IOC基于XML和注解管理Bean(二)的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處: 如若內容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • Spring基于注解管理bean及全注解開發(fā)

    Spring基于注解管理bean及全注解開發(fā)

    Spring是一款主流的Java EE 輕量級開源框架,目的是用于簡化Java企業(yè)級引用的開發(fā)難度和開發(fā)周期。從簡單性、可測試性和松耦合度的角度而言,任何Java應用都可以從Spring中受益。Spring框架提供自己提供功能外,還提供整合其他技術和框架的能力。 Spring自誕生以來備受青睞,

    2024年02月14日
    瀏覽(64)
  • Spring-1-透徹理解Spring XML的Bean創(chuàng)建--IOC

    Spring-1-透徹理解Spring XML的Bean創(chuàng)建--IOC

    上一篇文章我們介紹了什么是Spring,以及Spring的一些核心概念,并且快速快發(fā)一個Spring項目,實現IOC和DI,今天具體來講解IOC 能夠說出IOC的基礎配置和Bean作用域 了解Bean的生命周期 能夠說出Bean的實例化方式 問題導入 問題1:在 bean 標簽上如何配置別名? 問題2:Bean的默認作用

    2024年02月13日
    瀏覽(22)
  • 7、Spring之基于注解管理bean

    7、Spring之基于注解管理bean

    本質上:所有一切的操作都是Java代碼來完成的,XML和注解只是告訴框架中的Java代碼如何執(zhí)行。 創(chuàng)建名為spring_ioc_annotation的新module,過程參考3.1節(jié) 注解 含義 @Component 將類標識為普通組件 @Controller 將類標識為控制層組件 @Service 將類標識為業(yè)務層組件 @Repository 將類標識為持久

    2024年02月14日
    瀏覽(19)
  • 11Spring IoC注解式開發(fā)(上)(元注解/聲明Bean的注解/注解的使用/負責實例化Bean的注解)

    11Spring IoC注解式開發(fā)(上)(元注解/聲明Bean的注解/注解的使用/負責實例化Bean的注解)

    注解的存在主要是為了簡化XML的配置。Spring6倡導全注解開發(fā)。 注解開發(fā)的優(yōu)點 :提高開發(fā)效率 注解開發(fā)的缺點 :在一定程度上違背了OCP原則,使用注解的開發(fā)的前提是需求比較固定,變動較小。 自定義一個注解: 該注解上面修飾的注解包括:Target注解和Retention注解,這兩個注

    2024年01月21日
    瀏覽(30)
  • 【Spring進階系列丨第六篇】Spring的Bean管理(基于注解)

    【Spring進階系列丨第六篇】Spring的Bean管理(基于注解)

    回顧一下 基于xml配置的Spring對Bean的管理 ,對Bean的完整管理如下所示: 分析可以發(fā)現:我們對Bean的管理就四個方面,分別是: 用于創(chuàng)建對象的 用于注入數據的 用于改變Bean的作用域的 和Bean的生命周期相關的 其實對于注解來說,也是包括了這四個方面,換句話說, 使用注

    2024年02月03日
    瀏覽(26)
  • 【Spring進階系列丨第四篇】學習Spring中的Bean管理(基于xml配置)

    【Spring進階系列丨第四篇】學習Spring中的Bean管理(基于xml配置)

    在之前的學習中我們知道,容器是一個空間的概念,一般理解為可盛放物體的地方。在Spring容器通常理解為BeanFactory或者ApplicationContext。我們知道spring的IOC容器能夠幫我們創(chuàng)建對象,對象交給spring管理之后我們就不用手動去new對象。 那么Spring是如何管理Bean的呢? 簡而言之,

    2024年02月05日
    瀏覽(24)
  • Spring注解驅動開發(fā)之常用注解案例_告別在XML中配置Bean

    注解驅動開發(fā)就是不再使用Spring的bean.xml文件,改為純使用注解的方式開發(fā) @Configuration 此注解為配置類注解,相當于spring.xml文件,即配置類==配置文件 @Bean 給容器中注冊一個Bean;類型為返回值的類型,id默認是用方法名作為id 示例 Person類(后續(xù)注解配置類中都會以此類舉例),

    2024年01月21日
    瀏覽(28)
  • 【Spring篇】IOC/DI配置管理第三方bean

    【Spring篇】IOC/DI配置管理第三方bean

    ??系列專欄:Spring系列專欄 ??個人主頁:個人主頁 目錄 一、案例:數據源對象管理 1.環(huán)境準備 2.實現Druid管理 3.實現C3P0管理 二、加載properties文件 1.第三方bean屬性優(yōu)化 2.讀取單個屬性 3.注意事項 ? 三、核心容器 1.環(huán)境準備 2.容器 ? 1.容器的創(chuàng)建方式 2.Bean的三種獲取方式 3.容器

    2024年02月02日
    瀏覽(25)
  • Spring使用注解管理Bean

    Spring使用注解管理Bean

    引入lib包 Spring對Bean管理的常用注解 @Component組件(作用在類上) Spring中提供了@Component的三個衍生注解:(功能在目前為止是一致的) @Controller WEB層 @Service 業(yè)務層 @Repository 持久層 屬性注入的注解:(使用注解注入的方式,可以不用提供set方法) @Value? 用于注入普通類型 @Autowired? 自動裝

    2024年01月17日
    瀏覽(30)
  • 從入門到精通:掌握Spring IOC/DI配置管理第三方bean的技巧

    從入門到精通:掌握Spring IOC/DI配置管理第三方bean的技巧

    以后我們會用到很多第三方的bean,我們以數據源是 Druid(德魯伊) 和 C3P0 來配置舉個例子。 1.1.1 環(huán)境準備 先來準備下案例環(huán)境: 1.1.2 思路分析 需求:使用Spring的IOC容器來管理Druid連接池對象 1.使用第三方的技術,需要在pom.xml添加依賴 2.在配置文件中將【第三方的類】制作成一個

    2024年02月02日
    瀏覽(24)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包