SSM学习(高内聚低耦合)

1、IOC思想(充分解耦)

  1. Inversion of Control,控制反转,将JavaWeb中实现的new对象构建方法简化。

  2. 由主动new产生对象转换为由外部(IOC容器)提供对象,此过程中对象创建控制权由程序转移到外部

  3. IOC容器,负责对象的创建、初始化等工作,被创建或被管理的对象在IOC容器中统称为Bean

思考为什么在同一个IOC容器中依然可以实现service包调用dao包?

  1. 这里运用的就是DI(Dependency Injection)依赖注入(用于绑定关系)

    • 在容器中建立bean与bean之间的依赖关系的整个过程,称为依赖注入

image-20250408105806028

2、入门Spring

1. 文件的导入

  1. 在pom.xml文件中,加入spring-context的坐标,id为org.springframework

  2. 在resources目录中,创建applicationContext.xml文件

    1. 配置bean(通过application的接口实现类去调用方法)

//dao接口的实现类
package com.mao.dao.impl;
import com.mao.dao.BookDao;

public class BookDaoImpl implements BookDao {
    @Override
    public void save() {
        System.out.println("book dao save");
    }
}

//dao的接口
package com.mao.dao;

public interface BookDao {
    public void save();
}

//Service接口的实现类
package com.mao.service.impl;

import com.mao.dao.BookDao;
import com.mao.dao.impl.BookDaoImpl;
import com.mao.service.BookService;


public class BookServiceImpl implements BookService {
    private BookDao bookDao = new BookDaoImpl();//service中应先调用dao层,实现其接口
    @Override
    public void save() {
        System.out.println("book service save");
        bookDao.save();
    }
}

//Service接口,不可创建对象,所以需要new其实现类
package com.mao.service;

public interface BookService {
    public void save();
}

//测试类
import com.mao.dao.BookDao;
import com.mao.dao.impl.BookDaoImpl;
import com.mao.service.BookService;
import com.mao.service.impl.BookServiceImpl;

public class App {
    public static void main(String[] args) {
        //通过先调用service层,后service层中包含调用dao层,故产生两次输出
        //接口不可以创建对象,所以需要new它的实现类!!!!
        BookService bookService = new BookServiceImpl();
        bookService.save();
        System.out.println("=======================");
        //调用dao层
        BookDao bookDao = new BookDaoImpl();
        bookDao.save();
    }
}

第二种测试类:获取IOC容器、获取Bean调用方法

public class App2 {
    public static void main(String[] args) {
        //3.导入pom文件以及配置Bean后,现获取IOC容器(接口不可new对象,需要实例化其接口)
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        //4.获取IOC容器后,获取Bean(需要强转类型、引号中的内容为配置Bean的id)
        BookDao bookDao = (BookDao) ctx.getBean("bookDao");
        //获取bean后,可以调用其方法
        bookDao.save();
        System.out.println("==================");
        BookService bookService = (BookService) ctx.getBean("bookService");
        bookService.save();
    }
}

2. 通过注入IOC及DI注释来调用方法

<?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">
<!--    1.导入spring-context的坐标-->
<!--    2.配置bean-->
<!--    bean标签表示配置bean
        id属性表示给bean起名字(不可重复)
		name属性表示bean的别名,用空格分隔开,可能有多个别名,同时在获取bean时,引号中可以使用(name的范围很广,ref中也可以引用)
        class表示给bean定义类型
-->

<!--    <bean id="bookDao" class="com.mao.dao.impl.BookDaoImpl"></bean>
    <bean id="bookService" class="com.mao.service.impl.BookServiceImpl"></bean>-->

<!--    7.配置service和dao的关系-->
    <bean id="bookDao" class="com.mao.dao.impl.BookDaoImpl"></bean>
    <bean id="bookService" class="com.mao.service.impl.BookServiceImpl">
<!--
        property标签表示配置当前bean的属性
        name属性表示配置哪一个具体的属性(在Service接口实现类中定义的属性,private BookDao bookDao)
        ref属性表示参照哪一个bean,这里对应的是上面第一个配置的bean的id
-->
<!--        若这部分注释掉,则DI注入失败,也就是service和dao层的关系不明确,service层无法调用dao层的方法-->
        <property name="bookDao" ref="bookDao"></property>
    </bean>
</beans>

对应的是第五步、第六步

package com.mao.service.impl;

import com.mao.dao.BookDao;
import com.mao.dao.impl.BookDaoImpl;
import com.mao.service.BookService;


public class BookServiceImpl implements BookService {
/*    private BookDao bookDao = new BookDaoImpl();//service中应先调用dao层,实现其接口
    @Override
    public void save() {
        System.out.println("book service save");
        bookDao.save();
    }*/

    //5.删除业务层中使用new的方式创建的dao对象
    private BookDao bookDao;
    @Override
    public void save() {
        System.out.println("book service save");
        bookDao.save();
    }
    //6.提供对应的set方法
    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
    }

}

3. Bean的取别名及作用域(单例多例)

import com.mao.dao.BookDao;
import com.mao.service.BookService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App2 {
    public static void main(String[] args) {
        //3.导入pom文件以及配置Bean后,现获取IOC容器(接口不可new对象,需要实例化其接口)
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

        //4.获取IOC容器后,获取Bean(需要强转类型、引号中的内容为配置Bean的id)
        BookDao bookDao = (BookDao) ctx.getBean("dao");
        //获取bean后,可以调用其方法
        bookDao.save();
        System.out.println("==================");

        //这里的引号中,使用的是bean的别名引入
        BookService bookService = (BookService) ctx.getBean("service");
        bookService.save();

        //测试bookDao是否为单例对象(若不在bean配置中加scope,则默认是单例即singleton,则所有对象都是同一个地址)
        BookDao bookDao2 = (BookDao) ctx.getBean("dao");
        System.out.println(bookDao);
        System.out.println(bookDao2);
    }
}
<!--    7.配置service和dao的关系-->
    <bean id="bookDao" name="dao" class="com.mao.dao.impl.BookDaoImpl" scope="prototype"></bean>
    <bean id="bookService" name="service" class="com.mao.service.impl.BookServiceImpl" scope="prototype">
<!--
        property标签表示配置当前bean的属性
        id属性表示配置哪一个具体的属性(在Service接口实现类中定义的属性,private BookDao bookDao)
        ref属性表示参照哪一个bean,这里对应的是上面第一个配置的bean的id
-->
<!--        若这部分注释掉,则DI注入失败,也就是service和dao层的关系不明确,service层无法调用dao层的方法-->
        <property name="bookDao" ref="bookDao"></property>
    </bean>

4. 实例化Bean的三种方式

4.1 空参构造
//实例化Bean的方式(空参构造)不需要调用,默认访问空参构造(与访问域无关)
public BookDaoImpl() {
    System.out.println("dao constructor is running...");
}
4.2 静态工厂模式
<!--    Bean的实例化方式2     需要加factory-method才可以使用工厂模式 使用静态工厂实例化bean -->
    <bean id="orderDao" class="com.mao.factory.OrderDaoFactory" factory-method="getOrderDao"></bean>
//OrderDao接口的实现类
package com.mao.dao.impl;

import com.mao.dao.OrderDao;

public class OrderDaoImpl implements OrderDao {
    @Override
    public void save() {
        System.out.println("OrderDao save ... ");
    }
}

//OrderDao接口
package com.mao.dao;

public interface OrderDao {
    public void save();
}


//测试类,用于测试静态工厂实例化Bean
import com.mao.dao.OrderDao;
import com.mao.dao.impl.BookDaoImpl;
import com.mao.dao.impl.OrderDaoImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App3 {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        OrderDao orderDao = (OrderDao) ctx.getBean("orderDao");
        orderDao.save();
    }
}
4.3 实例化工厂模式(FactoryBean)
package com.mao.factory;

import com.mao.dao.UserDao;
import com.mao.dao.impl.UserDaoImpl;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.factory.FactoryBean;

public class UserDaoFactoryBean implements FactoryBean<UserDao> {

    //判断是否为单例,true为单例,false为多类型
    @Override
    public boolean isSingleton() {
        return true;
    }

    //代替原始实例工厂中创建对象的方法
    @Override
    public UserDao getObject() throws Exception {
        return new UserDaoImpl();
    }

    //返回类型对象为UserDao的字节码
    @Override
    public  Class<?> getObjectType() {
        return UserDao.class;
    }
}
public interface UserDao {
    public void save();
}

//接口的实现类
public class UserDaoImpl implements UserDao {
    @Override
    public void save() {
        System.out.println("UserDaoImpl.save");
    }
}

//测试类,测试FactoryBean实例化Bean
public class App3 {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
/*        OrderDao orderDao = (OrderDao) ctx.getBean("orderDao");
        orderDao.save();*/
        UserDao userdao1 = (UserDao) ctx.getBean("userdao");
        UserDao userdao2 = (UserDao) ctx.getBean("userdao");
        userdao1.save();
        System.out.println(userdao1);
        System.out.println(userdao2);
    }
}
<!--    方式四:FactoryBean模式实例化bean-->
    <bean id="userdao" class="com.mao.factory.UserDaoFactoryBean"></bean>

image-20250408215415127

image-20250408215507539

5. setter注入

<bean id="bookDao" name="dao" class="com.mao.dao.impl.BookDaoImpl" scope="prototype">
    <property name="connectionNum" value="10"></property>
    <property name="databaseName" value="mysql"></property>
</bean>

<bean id="bookService" name="service" class="com.mao.service.impl.BookServiceImpl" scope="prototype">
<!--
        id属性表示配置哪一个具体的属性(在Service接口实现类中定义的属性,private BookDao bookDao)
        name属性表示bean的别名,用空格分隔开,可能有多个别名,同时在获取bean时,引号中可以使用(name的范围很广,ref中也可以引用)
-->
<!--        若这部分注释掉,则DI注入失败,也就是service和dao层的关系不明确,service层无法调用dao层的方法
            property标签表示配置当前bean的属性     
			name则表示是类中的对象名
            ref属性表示参照哪一个bean,这里对应的是上面第一个配置的bean的id
-->
    <!--空参构造的注入-->
        <property name="bookDao" ref="bookDao"></property>
<!--        配置userdao的bean-->
        <property name="userDao" ref="userDao"></property>
</bean>

<!--构造器的注入-->
<property name="bookDao" ref="bookDao"></property>
<!--setter的注入-->
<property name="bookDao" value="bookDao"></property>
//引用类型注入(调用的话需要在xml文件中导入bean),同时提供set方法
private UserDao userDao;

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

    //定义简单类型
    private int connectionNum;
    private String databaseName;

    @Override
    public void save() {
        System.out.println("book dao save" + "," + connectionNum + "," + databaseName);
    }

image-20250410102359689

value:注入简单值(value会自动转换所需的类型),而ref则是注入引用类型,引入其他bean

6. 数据源对象管理

测试类,获取id为datasource的bean

public class App {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        DataSource datasource = (DataSource) ctx.getBean("datasource");
        System.out.println(datasource);
    }
}

导入几个依赖

<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>druid</artifactId>
  <version>1.2.24</version>
</dependency>
<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <version>8.0.32</version>
</dependency>
<dependency>
  <groupId>c3p0</groupId>
  <artifactId>c3p0</artifactId>
  <version>0.9.1.2</version>
</dependency>

分别交换id,用于测试,一个是Druid、一个是c3p0

<bean class="com.alibaba.druid.pool.DruidDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
    <property name="url" value="jdbc:mysql://localhost:3306/smbms"></property>
    <property name="username" value="root"></property>
    <property name="password" value="123456"></property>
</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/smbms"></property>
    <property name="user" value="root"></property>
    <property name="password" value="123456"></property>
</bean>

导入新的命名空间(加载制定的properties文件)

<!--引入新的命名空间,context-->
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       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
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd"
>

<!--    使用新的命名空间 context  (可实现动态获取)-->
    <context:property-placeholder location="jdbc.properties"></context:property-placeholder>
<!--动态获取jdbc的属性,使用占位符${属性名}     -->
    <bean class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driver}"></property>
        <property name="url" value="${jdbc.url}"></property>
        <property name="username" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>
<!--    引入BookDao,用于测试是否正确访问-->
    <bean id="bookDao" class="com.mao.dao.impl.BookDaoImpl">
        <property name="name" value="${jdbc.driver}"></property>
    </bean>

引入数据库信息

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/smbms
jdbc.username=root
jdbc.password=123456

测试类

public class App {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//        DataSource datasource = (DataSource) ctx.getBean("datasource");
//        System.out.println(datasource);
        BookDao bookDao = (BookDao) ctx.getBean("bookDao");
        bookDao.save();
    }
}

dao层

public interface BookDao {
    public void save();
}

public class BookDaoImpl implements BookDao {

//    用于测试是否生效,访问jdbc的文件
    private String name;

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

    @Override
    public void save() {
        System.out.println("save ..."+name);
    }
}

对context命名空间进行优化

<!--    加载所有的properties文件       system-properties-mode设置为永不访问系统的同名-->
    <context:property-placeholder location="classpath*:*.properties" system-properties-mode="NEVER"></context:property-placeholder>

image-20250410134543567

image-20250410134656859

7. 注解开发定义bean

扫描组件

<context:component-scan base-package="com.mao" ></context:component-scan>
//@Component("bookService")
//@Service
public class BookServiceImpl implements BookService {

    private BookDao bookDao;
//    private BookDao bookDao = new BookDaoImpl();//引入dao层(可以不写,在bean里引入即可!)

    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
    }

    @Override
    public void save() {
        System.out.println("bookService save...");
        //前面已经定义了bookDao,调用了dao层,那么就可以直接调用其方法了
//        bookDao.save();
    }
}
//@Component("bookDao")
@Repository("bookDao")
public class BookDaoImpl implements BookDao {
    @Override
    public void save() {
        System.out.println("bookDao save...");
    }
}
public class App {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//        DataSource datasource = (DataSource) ctx.getBean("datasource");
//        System.out.println(datasource);
        BookDao bookDao = (BookDao) ctx.getBean("bookDao");
        bookDao.save();

        //BookService bookService =  (BookService)ctx.getBean("bookService");
        BookService bookService =  ctx.getBean(BookService.class);
        bookService.save();
    }
}

7. 纯注解开发

这里的ClassPath加载被注解加载所替代:即AnnotationConfigApplicationContext,后面加载Java类的字节码文件,获取配置

public class AppForAnnotation {
    public static void main(String[] args) {
        ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
        BookDao bookDao = (BookDao) ctx.getBean("bookDao");
        bookDao.save();

        BookService bookService =  ctx.getBean(BookService.class);
        bookService.save();
    }
}

将applicationContext.xml文件改成java类来实现注解!

@Configuration则是bean的内容

@ComponentScan("com.mao")则是context命名空间的内容

package com.mao.config;

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

@Configuration
@ComponentScan("com.mao")
public class SpringConfig {
}

8. bean的作用范围和生命周期

@Repository
@Scope("prototype")
public class BookDaoImpl implements BookDao {
    @Override
    public void save() {
        System.out.println("bookDao save...");
    }
    @PostConstruct
    public void init() {
        System.out.println("init...");
    }
    @PreDestroy
    public void destory() {
        System.out.println("destory...");
    }
}
public class AppForAnnotation {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
        BookDao bookDao1 = ctx.getBean(BookDao.class);
        BookDao bookDao2 = ctx.getBean(BookDao.class);
        System.out.println(bookDao1);
        System.out.println(bookDao2);
        ctx.close();
        System.out.println(ctx.isClosed());

//        BookService bookService =  ctx.getBean(BookService.class);
//        bookService.save();
    }
}

9. 注解开发依赖注入

@Repository("bookDao")
@Scope("prototype")
public class BookDaoImpl implements BookDao {

    @Value("${name}")
    private String name;

    @Override
    public void save() {
        System.out.println("bookDao save..."+name);
    }
}
package com.mao.service.impl;

import com.mao.dao.BookDao;
import com.mao.dao.impl.BookDaoImpl;
import com.mao.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

@Service
public class BookServiceImpl implements BookService {
    //自动装配
    @Autowired
    private BookDao bookDao;
//    private BookDao bookDao = new BookDaoImpl();//引入dao层(可以不写,在bean里引入即可!)

    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
    }

    @Override
    public void save() {
        System.out.println("bookService save...");
        //前面已经定义了bookDao,调用了dao层,那么就可以直接调用其方法了
        bookDao.save();
    }
}
public class AppForAnnotation {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
        BookService bookService = context.getBean(BookService.class);
        bookService.save();
    }
}
 @Configuration
 @ComponentScan("com.mao")
 @PropertySource("jdbc.properties")
 public class SpringConfig {
 }
 name=com.mysql.cj.jdbc.Driver
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值