spring

Spring

一、简介

Spring 是一个开源的 Java/Kotlin 应用框架,它旨在简化企业级应用程序的开发。Spring 框架为开发者提供了一种全面编程和配置模型,用于现代基于 Java 的应用程序。Spring 框架的核心特性是控制反转(IOC)和面向切面编程(AOP),这些特性使得开发更加灵活和易于管理。spring就是一个轻量级的控制反转和面向切面的编程的框架

优点

  • spring是一个轻量级、非入侵的框架。
  • spring是一个开源免费的框架。
  • 控制反转(IoC) 和面向切面编程( AOP) 使得应用程序的各个部分更加独立,降低了模块间的耦合度。
  • 支持事务的处理,对框架整合的支持

二、IOC

简介

IOC即控制反转,是一种思想,是一种面向对象编程中的设计原则,主要用于解耦程序组件之间的依赖关系,DI(依赖注入)是实现IoC的一种方法。对象由spring创建、管理、装配

控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特点对象的方式。在Spring中实现控制反转的是Ioc容器,其实现方法是依赖注入(DI)。其实控制反转的目的就是为了达到分成解耦的效果。

分层解耦

分成解耦:软件工程中一种重要的设计思想和方法论,它通过分层和降低层次之间的耦合度来提高系统的灵活性、可维护性和可扩展性。


原来我们的代码是这样的

service实现层

public class serviceImpl {
    private DaoImpl d = new DaoImpl();

    private void gettest(){
        d.test();
    }
}

Dao实现层

public class DaoImpl {
    public void test(){
        System.out.println("test方法被调用");
    }
}

这样的代码需要在*service实现层创建对象,耦合度高,不利于管理,而且实际主动权在程序员,不具有多态性


控制反转后

service实现层

public class serviceImpl {
    private Dao d;

    public void setD(Dao d) {
        this.d = d;
    }

    public void gettest(){
        d.test();
    }
}

Dao接口层

public interface Dao {
    void test();
}

Dao实现层

public class DaoImpl implements Dao{
    @Override
    public void test(){
        System.out.println("test方法被调用");
    }
}

这样的就使得Dao实现层与service实现层进行了解耦,耦合度低,利于管理,实际主动权用户,具有多态性


依赖注入

依赖:Bean对象的创建依赖于容器

注入:Bean对象中的所有属性,由容器注入

(1)构造器注入

简介:基于构造函数的 DI 是通过容器调用带有许多参数的构造函数来完成的,每个参数代表一个依赖。

无参构造

Bean文件

<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="user" class="com.test.User">
        <property name="name" value="张三"/>
    </bean>
</beans>

实体类

public class User {
    private String name;

    public User() {
        System.out.println("User的无参构造被调用了");
    }

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

    public String getName() {
        return name;
    }
}

测试类

public class test {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
    }
}

当运行测试类后的结果

在这里插入图片描述


有参构造

(1)构造函数参数名

bean文件

<bean id="exampleBean" class="examples.ExampleBean">
    <constructor-arg name="name" value="张三"/>
</bean>

实体类

public class User {
    private String name;

    public User(String name) {
        System.out.println("User的有参构造被调用了");
    }

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

    public String getName() {
        return name;
    }
}

(2)构造函数参数索引(不实用,想了解可以看访问文档)

(3)构造函数参数类型匹配(不实用,想了解可以看访问文档)

问题1:在加载文件后Bean就被创建了吗??

结论1:当Bean文件被加载时,Bean对象就都创建好了


(2)Set注入

简介:基于 Setter 的 DI 是通过容器在调用无参数的构造函数或无参数的 static 工厂方法来实例化你的 bean 之后调用 Setter 方法来实现的。

各数据类型的注入方法,如下

pojo类

@Data
public class Student {
    private String name;
    private User user;    //这是个User类,里面有个name是个Sring类型
    private String[] arr;
    private List<String> list;
    private Map<String,String> map;
    private Set<String> set;
    private String nu;
    private Properties properties;
}

Bean文件

<bean id="user" class="com.qingshan.qingshan.Student">
        <property name="name" value="name" />
    
        <property name="user">
            <bean class="com.qingshan.qingshan.User">
                <property name="name" value="User_name" />
            </bean>
        </property>
                
        <property name="arr">
            <array>
                <value>arr1</value>
                <value>arr2</value>
                <value>arr3</value>
            </array>
        </property>
                
        <property name="nu">
            <null/>
        </property>
                
        <property name="list">
            <list>
                <value>1</value>
                <value>2</value>
            </list>
        </property>
                
        <property name="map">
            <map>
                <entry key="an entry" value="just some string"/>
                <entry key="a ref" value="myDataSource"/>
            </map>
        </property>

        <property name="set">
            <set>
                <value>info</value>
                <value>info1</value>
                <value>info1</value>
            </set>
        </property>

        <property name="properties">
            <props>
                <prop key="建1">1</prop>
                <prop key="建2">2</prop>
            </props>
        </property>
    </bean>

使用c命名空间的XML快捷方式

注:需要导入配置 xmlns:c=“http://www.springframework.org/schema/c”

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:c="http://www.springframework.org/schema/c"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="beanTwo" class="x.y.ThingTwo"/>
    <bean id="beanThree" class="x.y.ThingThree"/>

    <!-- 原本的写法 -->
    <bean id="beanOne" class="x.y.ThingOne">
        <constructor-arg name="thingTwo" ref="beanTwo"/>
        <constructor-arg name="thingThree" ref="beanThree"/>
        <constructor-arg name="email" value="something@somewhere.com"/>
    </bean>

    <!-- 使用c命名空间后 -->
    <bean id="beanOne" class="x.y.ThingOne" c:thingTwo-ref="beanTwo"
        c:thingThree-ref="beanThree" c:email="something@somewhere.com"/>

</beans>


使用p命名空间的XML快捷方式

注:需要导入配置 xmlns:p=“http://www.springframework.org/schema/p”

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean name="john-classic" class="com.example.Person">
        <property name="name" value="John Doe"/>
        <property name="spouse" ref="jane"/>
    </bean>

    <bean name="jane" class="com.example.Person">
        <property name="name" value="Jane Doe"/>
    </bean>
    
    <!-- 使用p名空间后 -->
    <bean name="john-modern"
        class="com.example.Person"
        p:name="John Doe"
        p:spouse-ref="jane"/>
    
</beans>

Bean的装配

在Spring中有三种装配的方式

(1)在xml中显示配置(以上用的都是这一种)
(2)在java中显示配置(重点、推荐)

Spring的Java配置支持的核心工件是 @Configuration 注解的类和 @Bean 注解的方法。

注入方法

@Configuration //加了这个注解相当于XML配置文件,底层也是IOC容器
@ComponentScan("com.test.pojo")  //组件扫描
@Import(mytest.class)  //加载其他的Configuration注册的类
public class AppConfig {
    //装配一个Bean,相当于一个Bean标签
    //方法名即是id名
    //方法的返回值就相当于class属性
    @Bean
    public MyServiceImpl myService() {
        return new MyServiceImpl();
    }
}

获取容器的方法

public static void main(String[] args) {
    AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
    ctx.scan("com.acme");
    ctx.refresh();
    MyService myService = ctx.getBean("myService");
}

(3)隐式的自动装配

没自动装配的

<bean id="cat" class="com.qingshan.qingshan.Cat" />
    <bean id="dog" class="com.qingshan.qingshan.Dog" />

    <bean id="person" class="com.qingshan.qingshan.People">
        <property name="cat" ref="cat" />
        <property name="dog" ref="dog" />
    </bean>

使用自动装配的

<bean id="cat" class="com.qingshan.qingshan.Cat" />
<bean id="dog" class="com.qingshan.qingshan.Dog" />

    <!--  byuName:会自动在容器上下文中查找,和自己对象属性名相同的Beanid  -->
    <!--  byuType:会自动在容器上下文中查找,和自己对象属性类型相同的Bean  -->
<bean id="person" class="com.qingshan.qingshan.People" autowire="byName" />

(4)注解实现自动装配

需要在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"
    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">
    
    <context:annotation-config/>
    
</beans>

@Autowired自动装配

自动装配到属性上,可以免去set方法的代码

public class VisualController {
    @Autowired
    private VisualService v1;
    
    @Autowired(required = false)  //将required设置为false,方法的参数可以为空
     public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }
}

@Resource自动装配

自动装配到属性上,可以免去set方法的代码,Resource是java自带的,脱离spring环境也可使用

public class SimpleMovieLister {
	@Resource
    private MovieFinder movieFinder;

    @Resource(name="my")    //可以设置name参数,表示找到Bean中id为my的装配
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }
}

@Qualifiers辅助装配

可以更加精准的装配到Bean

public class MovieRecommender {

    @Autowired
    @Qualifier(value="name")   //name为IOC容器中Bean的id名,
    private MovieCatalog movieCatalog;

    // ...
}

@Nullable

允许指定的属性为空

public class SimpleMovieLister {

    @Autowired
    public void setMovieFinder(@Nullable MovieFinder movieFinder) {
        ...
    }
}

注:@Resource @Nullable@Antowired等这些注解能被识别到,但是@Component、@Controller、@Service等这些注解不能被识别到,此时就需要用到 <context:component-scan >



Bean的作用域

有6种模式

在这里插入图片描述

单例模式(singleton)(默认)

不管怎么创建这个Bean对象都是始终用的唯一的一个bean对象

在这里插入图片描述

<bean id="accountService" class="com.something.DefaultAccountService" scope="singleton"/>
原型模式(prototype)

每次创建的bean对象都是不同的

在这里插入图片描述

<bean id="accountService" class="com.something.DefaultAccountService" scope="prototype"/>

Bean的别名

(1)使用name取别名(推荐,可取多个)

将Bean名称为user的取多个个别名分别为为u1和u2,多个别名之间用逗号隔开,可以使用这个别名获取到Bean对象
<bean id="user" class="com.qingshan.qingshan.User" name="u1,u2">
        <constructor-arg name="name" value="7500000"/>
</bean>

(2)使用alias取别名

将Bean名称为fromName的取一个别名为toName,可以使用这个别名获取到Bean对象
<alias name="fromName" alias="toName"/>

import 标签

一般用于团队开发,使用一个或多个 <import/> 元素的出现来从另一个或多个文件中加载Bean定义。

<beans>
    <import resource="services.xml"/>
    <import resource="resources/messageSource.xml"/>
    <import resource="/resources/themeSource.xml"/>
</beans>

三、使用注解开发

@Component

使用@Component将类注入Bean

使用@Compoent注解在类上相当于以下
<bean id="类名首字母小写" class="com.test" />

衍生注解

  • @Controller (控制层)
  • @Service (业务层)
  • @Repository (数据访问层)

这些注解的作用是一样的,只是为了好区别各层


@Value

使用@value注解给属性赋值

public class Dog {
    @Value("狗")
    private String name;
    void show(){
        System.out.println("狗叫");
    }
}

相当于xml的

<property name="name" value="" />

@value通常用于注入外部化properties。

@Component
public class MovieRecommender {

    private final String catalog;

    public MovieRecommender(@Value("${catalog.name}") String catalog) {
        this.catalog = catalog;
    }
}

catalog.name=MovieCatalog

@Scope

使用@Scope注解设置类的设计模式

//把类设为原型模式
@Scope("prototype"))
public class Test {

四、AOP

AOP,即面向切面编程,是一种编程范式,用于提高软件的可维护性、可扩展性和可重用性。它通过预编译方式和运行期间动态代理实现程序功能的统一维护,允许开发者在不修改源代码的情况下,为程序添加额外的功能。

在这里插入图片描述
通知类型

在这里插入图片描述

使用AOP需要导入依赖包需要导入依赖

<dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.21</version>
</dependecy>

(1)spring实现AOP

前置通知

public class Log implements MethodBeforeAdvice {
    /**
    * @Description: 前置通知
    * @Param: [method 要执行的目标对象方法, args 参数, target 目标对象]
    * @return: void
    * @Author: Lin
    * @Date:
    */
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
            System.out.println(target.getClass().getName()+"."+method.getName());
    }
}

后置通知

public class Log2 implements AfterReturningAdvice {
    /**
    * @Description: 后置通知
    * @Param: [returnValue 方法返回值, method 要执行的目标对象方法, args 参数, target 目标对象]
    * @return: void
    * @Author: Lin
    * @Date:
    */
    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("Log2: " + method.getName() + " return " + returnValue);
    }
}

Bean文件

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

    <bean id="userimpl" class="com.xing.springaop.UserImpl" />
    <bean id="log" class="com.xing.springaop.Log" />
    <bean id="log2" class="com.xing.springaop.Log2" />

    <aop:config>
        <!--切入点-->
        <aop:pointcut id="pointcut" expression="execution(* com.xing.springaop.UserImpl.*(..))" />

        <!--执行环绕增加-->
        <aop:advisor pointcut-ref="pointcut"  advice-ref="log"/>
        <aop:advisor pointcut-ref="pointcut"  advice-ref="log2"/>

    </aop:config>
</beans>

测试类

public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        //动态代理的是接口
        User user = (User) context.getBean("userimpl");
        user.add();
    }
}

(2) 自定义类实现AOP

dir类

public class Dir {
    public void before(){
        System.out.println("---------前置通知---------");
    }
    public void afterReturning(){
        System.out.println("---------后置通知---------");
    }
}

Bean文件

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

    <bean id="userimpl" class="com.xing.springaop.UserImpl" />
    <bean id="log" class="com.xing.springaop.Log" />
    <bean id="log2" class="com.xing.springaop.Log2" />
    <bean id="dir" class="com.xing.springaop.Dir" />
    <aop:config>
        <!--自定义的切面类:dir-->
        <aop:aspect ref="dir">
            <!--切入点-->
            <aop:pointcut id="poin" expression="execution(* com.xing.springaop.UserImpl.*(..))"/>
            
            <!--通知-->
            <aop:before method="before" pointcut-ref="poin" />
            <aop:after method="afterReturning" pointcut-ref="poin" />
        </aop:aspect>
    </aop:config>


</beans>

测试类

public class MyTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        //动态代理的是接口
        User user = (User) context.getBean("userimpl");
        user.add();
    }
}

(3) 注解实现

@Component //加载类为IOC容器
@Aspect  //设置类为切面
public class PointCut {
    //切入点
    @Before("execution(* com.xing.springaop.UserImpl.*(..))")
    public void before() {
        System.out.println("前置通知");
    }
	//切入点
    @After("execution(* com.xing.springaop.UserImpl.*(..))")
    public void after(){
        System.out.println("后置通知");
    }
}

五、声明式事务

1、事务

  • 将一组业务当成一次任务执行要么都成功,要么都失败
  • 使数据保持一致性

事务的ACID原则:

  • 原则性
  • 一致性
  • 隔离性
  • 持久性

事务类型

在这里插入图片描述

开启 Spring 的事务处理功能需要在spring的xml文件中加入以下内容

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  <constructor-arg ref="dataSource" />
</bean>

配置事务

<!--设置事务通知-->
<tx:advice id="txAdvuce" transaction-manager="transactionManager">
    <tx:attribute>
        <tx:method name="*" propagation="REQUIRED"/>  //表示在通知的事务中都开启REQUIRED事务
    </tx:attribute>
</tx:advice>

<!-- 配置事务的切入 -->
<aop:config>
    <aop:pointcut id="txPoinCut" expression="execution(* com.xing.springaop.*.*(..))" />
    <aop:advisor advice-ref="txAdvuce" pointcut-ref="txPoinCut" />
</aop:config>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值