spring入门

Spring是一个开源框架,为简化企业级开发而生。它以IOC(控制反转)和AOP(面向切面)为思想内核,提供了控制层SpringMVC、数据层SpringData、服务层事务管理等众多技术,并可以整合众多第三方框架。所以今天就开始学习spring,开始spring入门。
spring

这是spring的体系结构,这些模块可以满足很多企业级开发。其中的core Container是spring的核心模块。

IOC(控制反转)

控制反转:程序将创建对象的权利交给框架。在之前我们创建对象时通过new关键字手动创建的,也就是调用者管理对象。
通过手动创建的形式有两个缺点:
1.浪费资源:如果在方法中要创建对象,那么我们每次调用一次这个方法就要创建一个这个对象,如此一来就会创建大量对象,浪费资源。
2.代码的耦合度高:举个栗子,我们创建一个接口,也创建了一个实现类,随着开发,我又创建了一个更好的实现类,那我就必须修改源码。

通过spring实现IOC

在spring中有一个容器来管理对象。我们使用maven来演示spring的用法。
在maven中我们要引入的依赖如下:
spring的依赖:org.springframework spring-context
测试依赖:junit junit
编写applicationcontext.xml文件:

<?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 id="studentDao"class="com.hk.dao.StudentDaoImpl">
</bean>
</beans>

创建domain类和Dao类

public class Student {
    private int id;
    private String name;
    private String address;
 // 省略getter/setter/构造方法/tostring
}
public interface StudentDao {
    // 根据id查询学生
    Student findById(int id);
}
public class StudentDaoImpl implements
StudentDao{
    @Override```
    public Student findById(int id) {
        // 模拟从数据库查找出学生
        return new Student(1,"k","jx");
   }
}

//测试类

public class TestStudentDao {
    @Test
    public void testSelectById(){
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        StudentDao studentDao = (StudentDao) ac.getBean("studentDao");
        Student student = studentDao.selectById(1);
        System.out.println(student);
    }
}

运行结果
在测试时我们并没有手动创建实现类,而死从容器中把对象取出来用,这就是最简单的控制反转IOC。

spring容器类型

Spring容器中的顶层接口是BeanFactory,ApplicationContext是BeanFactory的子接口。ApplicationContext有以下三个常用实现类:
不同的实现类读取文件位置不同
ClassPathXmlApplicationContext:该类可以从项目中读取配置文件
FileSystemXmlApplicationContext:该类从磁盘中读取配置文件
AnnotationConfigApplicationContext:使用该类不读取配置文件,而是会读取注解

对象创建方式

我们平时都是用new关键字来创建对象,那么spring容器是通过什么方式来创建对象呢?
默认是使用空参构造法来创建对象,那么加入类中没有空参构造,怎么办呢?这时候我们可以通过调用工厂类来创建对象。
创建工厂类,并提供创建对象的方法
这是非静态方法

public class StudentDaoFactory {
    public StudentDao getStudentDao(){
        return new StudentDaoImpl(1);
   }
}
<!-- id:工厂对象的id,class:工厂类 -->
<bean id="studentDaoFactory"
class="com.itbaizhan.dao.StudentDaoFactory
"></bean>
<!-- id:bean对象的id,factory-bean:工厂对象
的id,factory-method:工厂方法 -->
<bean id="studentDao" factory-bean="studentDaoFactory" factory-method="getStudentDao"></bean>

这是静态方法

public class StudentDaoFactory2 {
    public static StudentDao getStudentDao2() {
        return new StudentDaoImpl();
   }
}
<!-- id:bean的id class:工厂全类名 factory-method:工厂静态方法   -->
<bean id="studentDao"class="com.hk.dao.StudentDaoFactory2" factory-method="getStudentDao2"></bean>

在配置文件中的写法是有点区别的。

对象的创建策略和销毁时机

只要在中添加属性scope就可以设置对象的创建策略,那么创建策略是什么,通俗的讲就是容器会创建几个对象,一共有5种创建策略:
singleton:单例,默认策略。整个项目只会创建一个对象,这是默认的,通过 中的 lazy-init 属性可以设置单例对象的创建时机:false是立即创建这是默认的,而true是延迟创建,第一次使用bean对象才会创建。销毁时机:对象随着容器的销毁而销毁。
prototype:多例,每次从容器中获取时都会创建对象。销毁时机:使用JAVA垃圾回收机制销毁对象。
request:每次请求创建一个对象,只在web环境有效。销毁时机:当处理请求结束,bean实例将被销毁。
session:每次会话创建一个对象,只在web环境有效。销毁时机:当HTTP Session最终被废弃的时候,bean也会被销毁掉。
gloabal-session:一次集群环境的会话创建一个对象,只在web
环境有效。销毁时机:集群环境下的session销毁,bean实例也将被销毁。

生命周期方法

bean对象的生命周期包含创建、使用和销毁,在spring中是可以配置bean对象在创建和销毁时自动执行的方法。
定义一个StudentDao的实现类加入init方法和destroy方法,并通过bean配置到容器中,bean中的init属性与destroy属性分别加入这连个方法

public class StudentDaoImpl2 implements StudentDao{
    public void init(){
        System.out.println("创建StudentDao");
    }
    public void destroy(){
        System.out.println("销毁StudentDao");
    }

    public Student selectById(Integer id) {
        return null;
    }
}
<bean id="studentDao" class="com.hk.dao.StudentDaoImpl2" scope="singleton" init-method="init" destroy-method="destroy"></bean>

测试

@Test
    public void t1(){
        ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        //销毁容器
        ac.close();
    }

运行结果

获取Bean对象的方式

spring中有多种获取对象的方式
1.通过id/name获取:此时需要强制类型转换
2.通过类型获取:不需要强制类型转换
3.通过类型+id/name获取:更加精确

ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        StudentDao studentDao = (StudentDao) ac.getBean("studentDao");
        StudentDao studentDao1 = ac.getBean(StudentDao.class);
        StudentDao studentDao2 = ac.getBean("studentDao", StudentDao.class);
        Student student = studentDao.selectById(1);
        Student student1 = studentDao1.selectById(1);
        Student student2 = studentDao2.selectById(1);
        System.out.println(student);
        System.out.println(student1);
        System.out.println(student2);

运行结果

依赖注入

什么是依赖注入

依赖注入是控制反转的具体实现,控制反转是将创建对象的权力交给容器,但是对象中可能会依赖其他对象,这时候就需要依赖注入。

public class StudentService {
    //不是用注入时,我们需要手动注入属性值
    private StudentDao studentDao;
    public Student findStudentById(Integer id){
        return studentDao.selectById(id);
    }
}

这样写的弊端是,比如说,当我的studentService想要想要使用StudentDao的另一个实现类时,需要修改源码,这样耦合度就很高,代码的可维护性降低,使用spring之后,spring管理Service对象与Dao对象,此时它能够为Service对象注入依赖的Dao属性值。

依赖注入的方式

在之前开发,我们想要设置对象属性可以使用setter方法和构造方法。所以依赖注入也可以有两种注入方式
1.setter注入:一定记得在StudentService中添加setter方法

<bean id="studentDao" class="com.huangkai.dao.StudentDaoImpl"></bean>
    <bean id="studentService" class="com.hk.service.StudentService">
    <!--name:对象的属性名 ref:容器中对象的id值-->
   <property name="studentDao" ref="studentDao"></property>
</bean>

2.构造方法注入:同样被注入类(StudentService)编写有参的构造方法

<bean id="studentDao"class="com.hk.dao.StudentDaoImpl">
</bean>
<bean id="studentService" class="com.hk.service.StudentService">
    <!-- name:对象的属性名 ref:配置文件中注入对象的id值 -->
    <constructor-arg name="studentDao"ref="studentDao"></constructor-arg>
</bean>

3.自动注入
自动注入不需要在Bean中添加其他标签的属性值,而是自动从容器中找到相应的bean对象设置为属性值。因为是自动,所以我们要加入一些配置:
1.全局配置:在 中设置 default-autowire 属性可以定义所有bean对象的自动注入策略。
2.局部配置:在 中设置 autowire 属性可以定义当前bean对象的自动注入策略。
autowire的取值如下:
no:不会进行自动注入。
default:全局配置default相当于no,局部配置default表示使用全局配置
byName:在Spring容器中查找id与属性名相同的bean,并进行注入。需要提供set方法。
byType:在Spring容器中查找类型与属性类型相同的bean,并进行注入。需要提供set方法。
constructor:在Spring容器中查找id与属性名相同的bean,并进行注入。需要提供构造方法。
举个栗子:

<bean id="studentDao" class="com.huangkai.dao.StudentDaoImpl"></bean>
    <bean id="studentService" class="com.huangkai.service.StudentService" autowire="byName"></bean>

这样子写就是当StudentService需要使用StudentDao时,StudentService就会直接从容器中匹配有没有id名字与studentService匹配的,一定要注意setter方法和构造方法,不要忘记加上。

依赖注入的类型

依赖注入支持注入bean类型、基本数据类型和字符串、List集合、Set集合、Map集合、Properties对象类型等。

通过注解实现springIOC

注解实现IOC要在配置文件中添加东西所以添加一个新的配置文件

<?xml version="1.0" encoding="UTF-8"?>
<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">
</beans>

@Component

作用:用于创建对象,放入Spring容器,相当于 bean id=“” class=“”
位置:类上方
我们直接写注解,spring容器是不知道的,想要通过注解加入到容器中我们要在配置类中添加配置

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

@Repository、@Service、@Controller

作用:这三个注解和@Component的作用一样,使用它们是为了区分该类属于什么层。
@Repository用于Dao层
@Service用于Service层
@Controller用于Controller层

@Scope

作用:指定bean的创建策略
位置:类上方
取值:singleton prototype request session globalsession

@Autowired

作用:从容器中查找符合属性类型的对象自动注入属性中。用于代替 中的依赖注入配置。
位置:属性上方、setter方法上方、构造方法上方。
写在属性上方进行依赖注入时,可以省略setter方法。

@Qualifier

作用:在按照类型注入对象的基础上,再按照bean的id注入。
位置:属性上方
注意:@Qualifier必须和@Autowired一起使用。

@Value

作用:注入String类型和基本数据类型的属性值。
位置:属性上方
注意注入配置文件的值时,写法是这样@Value(“${jdbc.username}”)

@Configuration

此时基于注解的IOC配置已经完成,但是我们依然离不开Spring的xml配置文件。接下来我们脱离bean.xml,使用纯注解实现IOC。就算使用纯注解,我们还是会保留配置文件。

@ComponentScan

作用:指定spring在初始化容器时扫描的包。
位置:配置类上方

@PropertySource

作用:代替配置文件中的 context:property-placeholder 扫描配置文件
位置:配置类上方
注意:配置文件位置前要加关键字 classpath

@Bean

作用:将方法的返回值对象放入Spring容器中。如果想将第三方类的对象放入容器,可以使用@Bean
位置:配置类的方法上方。
属性:name:给bean对象设置id
注意:@Bean修饰的方法如果有参数,spring会根据参数类型从容器中查找可用对象。

@Import

作用:如果配置过多,会有多个配置类,该注解可以为主配置类导入其他配置类
位置:主配置类上方

AOP(面向切面)

面向切面:在不修改源码的基础上,对已有的方法进行增强,主要作用在事务处理、日志管理、权限控制、异常处理等方面。
aop中有一些术语:
连接点:指能被拦截到的点,在spring中只有方法能被拦截。
切点:指要对哪些拦截点进行拦截,就是要被增强的方法。
通知:拦截后要做的事,就是拦截后执行的方法。
切面:切点+通知
相关术语图

AOP的通知类型

aop有五种通知类型
1.前置通知(before):在方法执行前添加功能
2.后置通知(after-returning):在方法正常执行后添加功能
3.异常通知(after-throwing):在方法抛出异常后添加功能
4.最终通知(after):无论方法是否抛出异常,都会执行该通知
5.环绕通知(around):在方法执行前后添加功能

切点表达式

标准写法:访问修饰符 返回值 包名.类名.方法名(参数列表)
访问修饰符可以省略。
返回值使用 * 代表任意类型。
包名使用 * 表示任意包,多级包结构要写多个 * ,使用 … 表示任意包结构
类名和方法名都可以用 * 实现通配。
参数列表:基本数据类型直接写类型
引用类型写 包名.类名
* 表示匹配一个任意类型参数
… 表示匹配任意类型任意个数参数
全通配: * .
(…)

Aspectj编写AOP

Aspectj是一个基于Java语言的AOP框架,我们使用Aspectj来实现AOP
举一个简单的栗子:在一个新增方法中添加后置通知
先引入依赖

<dependencies>
    <!-- spring -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.3.13</version>
    </dependency>
    <!-- AspectJ -->
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.8.7</version>
    </dependency>
    <!-- junit -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
</dependencies>

先编写Dao类

@Repository
public class UserDao {
    public void add(){
        System.out.println("新增用户");
    }
}

编写通知类

public class MyAspectJAdvice {
    // 后置通知
    public void myAfterReturning() {
        System.out.println("打印日志...");
   }
}

在配置类中引入依赖

<?xml version="1.0" encoding="UTF-8"?>
<beans
        xmlns="http://www.springframework.org/schema/beans"

        xmlns:context="http://www.springframework.org/schema/context"

        xmlns:aop="http://www.springframework.org/schema/aop"
        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

http://www.springframework.org/schema/aop

http://www.springframework.org/schema/aop/spring-aop.xsd">
    <context:component-scan base-package="com.huangkai"></context:component-scan>
    <!--通知对象-->
    <bean id="myAspectJAdvice" class="com.hk.Aspectj.MyAspectjAdvice"></bean>
    <!--配置AOP-->
    <aop:config>
        <!--配置斜面-->
        <aop:aspect ref="myAspectJAdvice">
            <!--配置切点-->
            <aop:pointcut id="myPointcut" expression="execution(* com.huangkai.Dao.UserDao.*(..))"/>
            <aop:after-returning method="myAfterRunning" pointcut-ref="myPointcut"/>
        </aop:aspect>
    </aop:config>
</beans>

写法都是固定的,只要依葫芦画瓢就行。测试一下

public class UserDaoTest {
    @Test
    public void testAdd(){
        ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserDao userDao = (UserDao) ac.getBean("userDao");
        userDao.add();
    }
}

运行结果

注解配置AOP

可以使用注解替代配置文件配置切面
先要在xml中开启注解支持

<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

在通知类上加上@Aspect,在通知方法上加入@Before/@AfterReturning/@AfterThrowing/@After/@Around即可

public class UserDaoTest {
    @Test
    public void testAdd(){
        ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserDao userDao = (UserDao) ac.getBean("userDao");
        userDao.add();
    }
}

除了Aspecj,当然也可以使用原生Java代码来实现,先掌握Aspectj即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值