Spring IoC(基于xml和基于注解)

  • Spring的初衷:

1、JAVA EE开发应该更加简单。
2、使用接口而不是使用类,是更好的编程习惯。Spring将使用接口的复杂度几乎降低到了零。
3、为JavaBean提供了一个更好的应用配置框架。
4、更多地强调面向对象的设计,而不是现行的技术如JAVA EE。
5、尽量减少不必要的异常捕捉。
6、使应用程序更加容易测试。

  • 核心容器

是Spring框架最基础的部分,它提供了依赖注入(DependencyInjection)特征来实现容器对Bean的管理。这里最基本的概念是BeanFactory,它是任何Spring应用的核心。BeanFactory是工厂模式的一个实现,它使用IoC将应用配置和依赖说明从实际的应用代码中分离出来。

  • 获取核心容器

    • ApplicationContext的三个常用类
      • ClassPathXmlApplicationContext:它可以加载类路径下的配置文件,要去配置文件必须在类路径下,不在的话,加载不了。
      • FileSystemXmlApplicationContext:它可以加载磁盘任意路径下的配置文件(但是必须要有访问权限)
      • AnnotationConfigApplication:它是用于读取注解创建容器的
    • 两个接口
      • applicationContext采用立即加载,读完配置文件立即创建对象
      • beanFactory采用延时加载,什么时候ud获取了对象,什么时候才真正的创建对象
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
  • 使用spring会使用到的相关依赖
    <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>
        <dependency>
            <groupId>commons-dbutils</groupId>
            <artifactId>commons-dbutils</artifactId>
            <version>1.7</version>
        </dependency>
        <dependency>
            <groupId>c3p0</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.1.2</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
                <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.7.RELEASE</version>
        </dependency>
    </dependencies>
  • Spring的配置

spring配置的前面部分的信息可以去官网下载,下载后通过查询并粘贴到xml文件中
在这里插入图片描述
打开core.html后可通过Ctrl+F进行查询
在这里插入图片描述
< bean>标签之前即为spring的配置,根据自己需要复制粘贴到自己项目中的配置文件中

  • 基于xml配置的配置文件

    <!--把对象的创建交给Spring来管理-->
    <!--spring对bean的管理细节
        1.创建bean的三种方式
            1.1方式一 使用默认构造函数创建,在spring的配置文件中使用bean标签,配以id和class属性,
            没有其他属性,采用的就是默认构造函数创建bean对象,此时若类中没有默认构造函数,则对象无法创建-->
<!--    <bean id = "accountService" class="service.impl.AccountServiceImpl"></bean>-->
    <bean id="accountDao" class="dao.impl.AccountDao"></bean>
    <!--1.2方式二 使用普通工厂中的方法创建对象(使用某个类中的方法创建对象,并存入spring容器)-->
<!--    <bean id="instanceFactory" class="factory.InstanceFactory"></bean>-->
<!--    <bean id="accountService" factory-bean="instanceFactory" factory-method="getAccountService"></bean>-->
    <!--1.3方式三 使用工厂中的静态方法创建对象(使用某个类中的静态方法创建对象,并存入spring容器中-->
<!--    <bean id="accountService" class="factory.StaticFactory" factory-method="getAccountService"></bean>-->

    <!--2.beam的作用范围调整
        bean标签的scope属性
            作用:用于指定bean的作用范围
            取值:singleton 单例的(常用)
                  prototype 多例的(常用)
                  request 作用于web应用的请求范围
                  session web用于的会话范围
                  global-session 集群环境的会话范围
    -->
<!--    <bean id="accountService" class="service.impl.AccountServiceImpl" scope="singleton"></bean>-->

    <!-- bean对象的声明周期
            单例对象
                出生:容器创建对象出生,即解析配置文件时创建对象
                活着:只要容器未被销毁,对象一直活着
                死亡:容器销毁,对象消亡
                总结:单例对象的生命周期和容器相同
             多例对象
                出生:当我们使用对象时Spring框架为我们创建
                活着:对象只要是在使用过程中就一直活着
                死亡:对象长时间不使用且没有别的对象引用时,由java垃圾回收期回收
          -->
<!--        <bean id="accountService" class="service.impl.AccountServiceImpl"-->
<!--              scope="prototype" init-method="init" destroy-method="destory"></bean>-->

    <!--Spring 中的依赖注入(dependency injection
        IOC的作用降低耦合(依赖关系)
        依赖关系的管理:交给spring来维护
        当前类需要用到其他类的对象,由spring为我们提供,我们只需啊哟在配置文件中说明
        依赖关系的维护成为依赖注入
        能注入的数据:基本类型和String
                     其他bean类型(在配置文件或注解配置过的bean)
                     复杂类型/集合类型
        注入的方式:使用构造函数提供
                    使用set方法提供
                    使用注解提供

    -->
<!--    构造函数注入
        使用的标签:constructor-arg
        标签出现的位置:bean标签的内部
        标签中的属性 type:用于指定要注入的数据的数据类型,该数据类型也是构造函数中某个或某些参数的类型
                    index:用于指定要注入的数据给构造函数中指定索引未知的额参数赋值。索引位置从0开始
                    name:用于指定给构造函数中指定名称的参数赋值
                    ========上面三个方法用于指定给构造函数中的那个参数赋值
                    value:用于提供基本类型和String类型的数据
                    ref:用于指定其他的bean类型数据。他值得就是在Spring的IOC核心容器中出现过的bean
        优势:获取bean对象时。注入的数据是必须的操作,否则对象无法创建成功
        弊端:改变了bean对象实例化方式,创建对象时,如果用不到这些数据,也必须提供
        -->
        <!--    此时类中没有默认空参构造器-->
                <bean id="accountService" class="service.impl.AccountServiceImpl">
                    <constructor-arg name="name" value="test"></constructor-arg>
                    <constructor-arg name="age" value="18"></constructor-arg>
                    <constructor-arg name="birthday" ref="now"></constructor-arg>
                </bean>

                <bean id="now" class="java.util.Date"></bean>
<!-- set方法的注入
        设计的标签property
        出现的位置bean标签的内部
        标签的属性
             name:用于指定给构造函数中指定名称的参数赋值
            value:用于提供基本类型和String类型的数据
            ref:用于指定其他的bean类型数据。他指的就是在Spring的IOC核心容器中出现过的bean-->

<!--复杂类型的注入-->
    <!-- 用于给List结构集合注入数据的标签:list array set
         用于给map结构集合注入数据的标签:map props
         结构相同标签可以互换-->

</beans>
  • 基于注解的配置文件,要注意基于注解的bean.xml的头部和基于xml的不相同,这个也可以去刚才那个html中查找
<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">
    <!--告诉spring在创建容器时要扫描的包,配置所需要的标签不是在bean的约束中,
    而是一个名称为context名称空间和约束中-->
    <context:component-scan base-package="com.boogie"></context:component-scan>
</beans>

基于注解的相关注解

  • 用于创建对象的
    • 与xml中标签功能相同
    • @Component:把当前类对象存入spring容器中
      • 属性:value 指定bean的id,不写时默认是当前类名第一个字母改小写
    • 以下三个注解的作用和Component的作用一样,是spring框架为我们明确的三层使用的注解,让我们对三层对象更加清晰
    • @Controller:一般在表现层
    • @Service:一般在业务层
    • @Repository:一般在持久层
  • 用于注入数据的
    • 与xml文件中bean标签中标签作用相同
    • @Autowired:自动按照类型注入。只要容器中有唯一一个bean对象类型和要注入的变量类型匹配,就可以注入成功
      • 如果IOC容器中没有任何bean类型和要注入的变量类型匹配,则报错
      • 如果IOC容器中有多个类型匹配时:先按照类型找到匹配类型,再按照所定义的变量名称去找,若都不相同且有多个与之匹配的,则报错
      • 出现位置:变量或方法
      • 细节:使用注解时set方法不是必须的
    • @Qualifier:在按照类注入的基础上在按照名称注入,他在给类成员注入时不能单独使用但是在给方法注入参数时可以
    • @Resource:直接按照bean的id注入,可以独立使用
      • 属性:name:用于指定bean的id
    • 以上三个注解只能注入其他bean类型的数据,二基本类型和String类型无法使用上述注解实现
    • 另外,集合类型的注入只能通过xml来实现
    • @Value:用于注入基本类型和String类型的数据
      * 属性:用于指定数据的值,它可以使用spring中的el表达式
      * SpEL的写法:${表达式}
  • 用于改变作用范围的
    • 与xml文件中bean标签使用的scope属性功能相同
    • @Scope:用于指定bean的作用范围
      • 属性:singleton prototype分别对应单例和多例
      • 默认情况是单例的
  • 和生命周期相关
    • 与xml文件中bean标签中init-method和destory-method作用相同
    • @PreDestory:用于指定销毁方法
    • @postConstruct:用于指定初始化方法
//一个小例子,可以体会一下各个注解的使用
@Service("accountService")
public class AccountServiceImpl implements IAccountService {

//    @Autowired
//    @Qualifier("accountDao")//它不能独立使用
    @Resource(name = "accountDao")
    private IAccountDao accountDao;

    public AccountServiceImpl(){
        System.out.println("创建对象");
    }
    
    @PostConstruct
    public void init(){
        System.out.println("初始化...");
    }

    @PreDestroy
    public void destroy(){
        System.out.println("销毁...");
    }

    @Override
    public void saveAccount() {
        accountDao.saveAccount();
    }
}

下面附上一个spring的实例,可以更好地理解Spring的容器的概念
项目结构

  1. 首先创建与数据库相关实体类
public class Account implements Serializable {
    private Integer id;
    private String name;
    private Float money;

    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;
    }

    public Float getMoney() {
        return money;
    }

    public void setMoney(Float money) {
        this.money = money;
    }

    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", money=" + money +
                '}';
    }
}
  1. 创建dao接口类以及实现类
public interface IAccountDao {

    List<Account> findAllAcount();

    Account findAccountById(Integer id);

    void saveAccount(Account account);

    void updateAccount(Account account);

    void deleteAccount(Integer id);

    Account findAccountByName(String name);

}
@Repository("accountDao")
public class AccountDao implements IAccountDao {

//    private IAccountDao accountDao;
    private QueryRunner ruuner;
    private ConnectionUtils connectionUtils;

    public void setConnectionUtils(ConnectionUtils connectionUtils) {
        this.connectionUtils = connectionUtils;
    }

    public void setRuuner(QueryRunner ruuner) {
        this.ruuner = ruuner;
    }

    @Override
    public List<Account> findAllAcount() {
        try {
            return ruuner.query(connectionUtils.getThreadConnection(),"select * from account",new BeanListHandler<Account>(Account.class));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public Account findAccountById(Integer id) {
        try {
            return  ruuner.query(connectionUtils.getThreadConnection(),"select * from account where id=?",new BeanHandler<Account>(Account.class),id);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void saveAccount(Account account) {
        try {
            ruuner.update(connectionUtils.getThreadConnection(),"insert into account(id,name,money) values(?,?,?)",account.getId(),account.getName(),account.getMoney());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void updateAccount(Account account) {
        try {
            ruuner.update(connectionUtils.getThreadConnection(),"update account set name=?,money=?  where id=?",account.getName(),account.getMoney(),account.getId());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void deleteAccount(Integer id) {
        try {
            ruuner.update(connectionUtils.getThreadConnection(),"delete from account where id=?",id);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public Account findAccountByName(String name) {
        try {
            List<Account> accounts=  ruuner.query(connectionUtils.getThreadConnection(),"select * from account where name=?",new BeanListHandler<Account>(Account.class),name);
            if (accounts==null||accounts.size()==0){
                return null;
            }
            if (accounts.size()>1){
                throw new RuntimeException("结果集不唯一,数据有问题");
            }
            return accounts.get(0);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
  1. 创建服务层接口以及实现类
public interface IAccountService {

    List<Account> findAllAcount();

    Account findAccountById(Integer id);

    void saveAccount(Account account);

    void updateAccount(Account account);

    void deleteAccount(Integer id);

    void transfer(String sourceName,String targetName,Float money);

}
@Service("accountService")
public class AccountServiceImpl implements IAccountService {

    @Autowired
    private IAccountDao accountDao;

    public void setAccountDao(AccountDao accountDao) {
        this.accountDao=accountDao;
    }
    
    @Override
    public void updateAccount(Account account) {

            accountDao.updateAccount(account);

    }

    @Override
    public void deleteAccount(Integer id) {

            accountDao.deleteAccount(id);
    }

    @Override
    public void transfer(String sourceName, String targetName, Float money) {

            //转账
            //2.1.根据名称查询转出账户
            Account source= accountDao.findAccountByName(sourceName);
            //2.2.根据名称转入账户
            Account target=accountDao.findAccountByName(targetName);
            //2.3.转出账户减钱
            source.setMoney(source.getMoney()-money);
            //2.4.转入账户加钱
            target.setMoney(target.getMoney()+money);
            //2.5.更新转出账户
            accountDao.updateAccount(source);
            //2.6.更新转入账户
            accountDao.updateAccount(target);

    }

    @Override
    public List<Account> findAllAcount() {

            List<Account> accounts =accountDao.findAllAcount();
        return accounts;
    }

    @Override
    public Account findAccountById(Integer id) {

            Account account =accountDao.findAccountById(id);

            return account;

    }

    @Override
    public void saveAccount(Account account) {
      accountDao.saveAccount(account);

    }


}

  1. 创建工具类
public class ConnectionUtils {

    private ThreadLocal<Connection> tl = new ThreadLocal<Connection>();

    private DataSource dataSource;

    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    /**
     * 获取当前线程的连接
     * @return
     */
    public Connection getThreadConnection(){
        //1.先从ThreadLocal上获取
        Connection conn=tl.get();
        //2.判断当前线程上是否有连接
        try {
            if(conn==null){
                //3.从数据源中获取一个连接,并存入ThreadLocal中
                conn=dataSource.getConnection();
                tl.set(conn);
            }
            //4.返回当前线程上的连接
            return conn;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public void removeConnection(){
        tl.remove();
    }
}

public class TransactionManager {

    private ConnectionUtils connectionUtils;

    public void setConnectionUtils(ConnectionUtils connectionUtils) {
        this.connectionUtils = connectionUtils;
    }

    /**
     * 开启事务
     */
    public void beginTransaction(){
        try {
            connectionUtils.getThreadConnection().setAutoCommit(false);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 提交事务
     */
    public void commit(){
        try {
            connectionUtils.getThreadConnection().commit();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 回滚事务
     */
    public void rollback(){
        try {
            connectionUtils.getThreadConnection().rollback();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 释放事务
     */
    public void release(){
        try {
            connectionUtils.getThreadConnection().close();//还回线程池
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

  1. 创建代理类
public class BeanFactory {

    private IAccountService accountService;

    public final void setAccountService(IAccountService accountService) {
        this.accountService = accountService;
    }
    private TransactionManager transactionManager;

    public void setTransactionManager(TransactionManager transactionManager) {
        this.transactionManager = transactionManager;
    }

    /**
     * 获取Service代理对象
     * @return
     */
    public IAccountService getAccountService(){
        return (IAccountService) Proxy.newProxyInstance(accountService.getClass().getClassLoader()
                , accountService.getClass().getInterfaces()
                , new InvocationHandler() {
                    /**
                     * 添加事务的支持
                     * @param proxy
                     * @param method
                     * @param args
                     * @return
                     * @throws Throwable
                     */
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        Object returnValue=null;
                        try {
                            //1.开启事务
                            transactionManager.beginTransaction();
                            // 2.执行操作
                            returnValue= method.invoke(accountService,args);
                            // 3.提交事务
                            transactionManager.commit();
                            // 4.返回结果
                            return returnValue;
                        } catch (Exception e) {
                            //5.回滚操作
                            transactionManager.rollback();
                            throw new RuntimeException(e);
                        } finally {
                            //6.释放连接
                            transactionManager.release();
                        }
                    }
                });

    }
}

  1. 配置
<!--配置代理的service-->
    <bean id="proxyAccountService" factory-bean="beanFactory" factory-method="getAccountService"></bean>

    <!--配置beanFactory-->
    <bean id="beanFactory" class="com.boogie.factory.BeanFactory">
        <!--注入service-->
        <property name="accountService" ref="accountService"></property>
        <!--注入事务管理器-->
        <property name="transactionManager" ref="transactionManager"></property>
    </bean>


    <!--配置业务层对象Service-->
    <bean id="accountService" class="com.boogie.service.impl.AccountServiceImpl">
        <!--注入Dao对象-->
        <property name="accountDao" ref="accountDao"></property>
    </bean>

    <!--配置持久层对象Dao-->
    <bean id="accountDao" class="com.boogie.dao.impl.AccountDao">
        <!--配置QueryRunner-->
        <property name="ruuner" ref="runner"></property>
        <!--注入connectionutils-->
        <property name="connectionUtils" ref="connectionUtils"></property>
    </bean>

    <!--配置QueryRunner-->
    <bean id="runner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype"></bean>

    <!--配置数据源-->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <!--连接数据库的信息-->
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/数据库名称"></property>
        <property name="user" value="root"></property>
        <property name="password" value="数据库密码"></property>
    </bean>

    <!--配置Connection的工具类ConnectionUtils-->
    <bean id="connectionUtils" class="com.boogie.utils.ConnectionUtils">
        <!--注入数据源        -->
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!--配置事务管理器-->
    <bean id="transactionManager" class="com.boogie.utils.TransactionManager">
        <!--注入connectionutils-->
        <property name="connectionUtils" ref="connectionUtils"></property>
    </bean>

</beans>
  1. 测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:bean.xml")
public class AccountServiceTest {

    @Autowired
    @Qualifier("proxyAccountService")
    private IAccountService as;

    @Test
    public void testFindAll() {

        List<Account> accounts=as.findAllAcount();
        for(Account account:accounts){
            System.out.println(account);
        }
    }
    @Test
    public void testFindOne() {
      Account account=as.findAccountById(1);
        System.out.println(account);
    }
    @Test
    public void testSave() {
        Account account= new Account();
        account.setId(5);
        account.setName("哈哈");
        account.setMoney((float) 5000.0);
        as.saveAccount(account);
    }
    @Test
    public void testUpdate() {
     Account account =as.findAccountById(5);
        account.setMoney((float) 6000.0);
        as.updateAccount(account);
    }
    @Test
    public void testDelete() {
      as.deleteAccount(5);
    }
    @Test
    public void testTraansfer(){
       as.transfer("aaa","bbb",100f);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1、Spring配置文件 Spring配置文件Spring框架中非常重要的一部分,它通常以XML格式编写,用于配置Spring应用程序中的各种组件,例如Bean、AOP、数据源、事务等。 在Spring配置文件中,最常用的标签是<bean>标签,用于定义和配置Spring IoC容器中的Bean对象。除此之外,还有<import>标签,用于引入其他配置文件;<aop:config>标签,用于配置AOP相关的切面和通知等;<tx:advice>标签,用于配置事务管理相关的通知等。 Spring配置文件的编写需要遵守一定的规范和约束条件,例如必须指定命名空间、必须定义命名空间的schema等。同时,Spring还提供了多种加载配置文件的方式,例如ClassPathXmlApplicationContext、FileSystemXmlApplicationContext等。 2、Spring IoC基于注解的操作和案例 除了使用XML配置文件之外,Spring IoC容器还支持基于注解的Bean定义和注入操作。在Spring中,使用注解可以大大简化配置文件的编写,提高开发效率和可读性。 常用的Spring注解包括: - @Component:用于标识一个组件,通常与@Autowired等注解一起使用。 - @Autowired:用于自动注入一个Bean对象。 - @Qualifier:用于指定一个Bean对象的名称。 - @Value:用于注入一个基本类型或String类型的属性值。 - @Configuration:用于标识一个配置类,通常与@Bean等注解一起使用。 - @Bean:用于定义一个Bean对象,通常用于@Configuration类中。 - @Profile:用于指定一个Bean对象的环境依赖。 下面是一个基于注解Spring IoC配置案例: ``` @Configuration public class AppConfig { @Bean public UserService userService() { return new UserServiceImpl(); } } ``` 在这个案例中,使用@Configuration注解表示这是一个配置类,使用@Bean注解表示定义了一个名为“userService”的Bean对象。该Bean对象的类型是UserServiceImpl。 另外,还可以使用@Autowired和@Qualifier注解来实现Bean的自动注入。例如: ``` @Service public class UserServiceImpl implements UserService { @Autowired @Qualifier("userRepository") private UserRepository userRepository; // ... } ``` 在这个案例中,使用@Service注解表示这是一个服务类,使用@Autowired注解表示自动注入一个名为“userRepository”的Bean对象。其中,@Qualifier注解用于指定Bean对象的名称。 总之,Spring配置文件和基于注解的操作是Spring框架中非常重要和常用的组件,它们为Java开发人员提供了一种高效、灵活和可维护的方式来管理对象和依赖关系。通过基于注解的方式,可以大大简化配置文件的编写工作,提高开发效率和可读性。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值