浅谈spring

本文详细介绍了Spring框架的核心特性,包括IOC容器和Beans的概念,依赖注入(DI)的实现,自动装配的配置文件和注解方式,以及Spring的注解开发。此外,还探讨了Spring中的面向切面编程(AOP),通过JavaAPI、自定义代理类和注解三种方式实现。最后,文章展示了Spring如何与MyBatis进行整合,实现了数据库操作的事务管理。
摘要由CSDN通过智能技术生成

目录

1. spring简介

2. spring ioc容器和Beans介绍

2.1 ioc是什么

2.2Beans是什么

2.3 获得容器及对象

2.3.1 实现如下实体类

2.3.2 配置元数据,实例化容器

2.3.3 获得对象,进行测试

 2.3.4最后,附上一个测试

3. DI

3.1简介

3.2 测试

4.自动装配

4.1配置文件实现自动装配

 4.2注解实现自动装配

5.spring注解开发

6. aop

6.1java api实现aop

6.2自定义代理类实现aop

 6.3注解实现aop

7.Spring整合Mybatis

7.1简述

7.2spring整合mybatis演示

8. Spring中的事务

8.1简述

8.2测试

8.3声明式事务


1. spring简介

spring在不同的上下文中有不同的含义,它可以指spring框架项目本身,也可以指整个项目家族。这篇文章关注于spring框架本身。

spring是的创建Java企业应用程序变得很容易,它提供了在企业环境中使用Java语言所需的一切。 

2. spring ioc容器和Beans介绍

2.1 ioc是什么

ioc(控制反转),简单举例来说,就是在获取Java对象的时候,对象的属性不会在类中就定义好,而是会通过set方法来允许用户自己设置。即:对象属性不再由程序员硬编码去控制,而是让用户去控制。

其实,一般我们也是这样做的。

2.2Beans是什么

Bean,其实也就相当于Java对象。使用spring后,获得一个实体对象不再需要new关键字了,你只需要获得一个ApplicationContext的容器,然后需要什么对象就直接用getBean方法就可以获取,不过别忘了强转类型。

也就是说,容器在创建的时候,就已经把在它注册文件里注册的对象 new出来了。并且,通过容器获得对象,这使用的是单例模式,也就是说,你用同样的id获得的多个对象,实际上都是同一个。对其中一个对象的属性进行操作,会使你获得的其它对象的属性也随之更改。

2.3 获得容器及对象

2.3.1 实现如下实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Good {
    private int id;
    private String name;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private int id;
    private String name;
    private Good good;
}

2.3.2 配置元数据,实例化容器

spring ioc容器使用 一种配置元数据的形式。这个配置元数据告诉spring容器如何在应用程序中实例化、配置和组装对象。这篇文章中,配置元数据以简单直观的xml格式提供。

配置元数据文件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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

<!--    class 要使用完全限定名-->
    <bean id="good" class="com.plane.pojo.Good">
        <property name="id" value="1"></property>
        <property name="name" value="辣条"></property>
    </bean>

    <bean id="user" class="com.plane.pojo.User">
        <property name="name" value="宏彬"></property>
        <property name="id" value="1"></property>
        <property name="good" ref="good"></property>
    </bean>

    <!-- more bean definitions go here -->

</beans>

利用配置元数据new 一个ClassPathXmlApplicationContext 对象, 获得一个ApplicationContext对象,这个ApplicationContext对象就是我们的spring容器。可以通过它的getBean方法获得对象。(ApplicationContextClassPathXmlApplicationContext的超类)

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

2.3.3 获得对象,进行测试

在测试中,通过user获得了user1和user2两个对象,对其中一个的属性进行修改,输出另外一个,发现两个的属性都变了

        User user1 = (User) context.getBean("user");
        System.out.println(user1);

        User user2 = (User)context.getBean("user");
        System.out.println(user1==user2);

        user2.setName("宏猪");
        System.out.println(user1);

 

 2.3.4最后,附上一个测试

        ApplicationContext context1 = new ClassPathXmlApplicationContext("applicationContext.xml");
        ApplicationContext context2 = new ClassPathXmlApplicationContext("applicationContext.xml");

        System.out.println("context1 和 context2是否是同一个对象:");
        System.out.println(context1==context2);
        System.out.println("=======================================");

        User user1 =  (User)context1.getBean("user");
        User user2 = (User)context2.getBean("user");
        System.out.println("c1 和 c2 获得的同id对象是不是同一个:");
        System.out.println(user1==user2);
        System.out.println("=================================");

        System.out.println("改变user1的属性,user2的属性是否会跟着改变:");
        user1.setName("5555555555555555555");
        System.out.println(user2);

 

            ===================

@Data
public class Constructor {
    public Constructor(){
        System.out.println("Constructor对象被创建出来了");
    }
}

public class Test {

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


    }
}

 

3. DI

3.1简介

DI,即依赖注入,就是bean对象的创建依赖于容器,bean对象的属性依赖于容器注入。

前面的文章中已经提到了基本类型属性和bean对象属性的注入,这一章节将会讲解其它类型的注入。

list | set | map | props | value | null

3.2 测试

创建如下实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    private String name;
    private List<String> hobbys;
    private Set<String> books;
    private Map<String, String> cards;
    private Properties info;
    private String wife;
}

编写student.xml文件

    <bean id="student" class="com.plane.pojo.Student">
        <property name="name" value="哼哼哼"></property>
        <property name="info">
            <props>
                <prop key="身高">172</prop>
                <prop key="体重">110</prop>
            </props>
        </property>

        <property name="hobbys">
            <list>
                <value>看视频</value>
                <value>写代码</value>
                <value>记笔记</value>
                <value>写博客</value>
            </list>
        </property>

        <property name="books">
            <set>
                <value>java核心技术</value>
                <value>csapp</value>
                <value>jvm</value>
            </set>
        </property>

        <property name="cards">
            <map>
                <entry key="身份证" value="555555111111110202"></entry>
                <entry key="学生卡" value="0000555111"></entry>
            </map>
        </property>

        <property name="wife">
            <null></null>
        </property>

测试

//    输出结果
//    Student(
//      name=哼哼哼, 
//      hobbys=[看视频, 写代码, 记笔记, 写博客], 
//      books=[java核心技术, csapp, jvm], 
//      cards={身份证=555555111111110202, 学生卡=0000555111}, 
//      info={身高=172, 体重=110}, 
//      wife=null)

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("student.xml");
        Student student = context.getBean("student", Student.class);
        System.out.println(student);

    }

4.自动装配

通过前面的文章我们已经知道,如何通过配置文件获得对象。这一章节将会讲到,当对象所需要的属性也是一个对象,且这个属性对象已经在配置文件中注册为bean的时候,如何将这个属性对象注入到所需对象,成为它的一个属性。 

4.1配置文件实现自动装配

定义如下所需类

@Data
@AllArgsConstructor
public class Dog {
    public void shout(){
        System.out.println("汪汪汪...");
    }
}
@Data
@NoArgsConstructor
public class Cat {
    public void shout(){
        System.out.println("喵喵喵...");

    }
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {

    private String name;
    private Cat cat;
    private Dog dog;
}

配置文件如下

<?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="cat" class="com.plane.pojo.Cat"></bean>
    <bean id="dog" class="com.plane.pojo.Dog"></bean>
    <bean id="person" class="com.plane.pojo.Person" autowire="byName">
        <property name="name" value="红猪"></property>
    </bean>

</beans>

测试结果

        ApplicationContext context = new ClassPathXmlApplicationContext("person.xml");
        Person person = context.getBean("person", Person.class);

        System.out.println(person.getName());
        person.getCat().shout();
        person.getDog().shout();

红猪
喵喵喵...
汪汪汪... 

 4.2注解实现自动装配

@Autowired 自动地从.xml文件中查找已注册的bean,当环境较为复杂、无法找到唯一合适的bean时,可以通过与@Qualifier(value = "xxx")配合使用,装配指定id的bean

注解实现自动装配需要时,beans标签需要引入依赖,并开始注解支持

<!--beans标签中导入了使用注解需要的依赖-->
<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/>


    <bean id="cat" class="com.plane.pojo.Cat"></bean>
    <bean id="cat22" class="com.plane.pojo.Cat"></bean>
    <bean id="dog" class="com.plane.pojo.Dog"></bean>
    <bean id="dog22" class="com.plane.pojo.Dog"></bean>
<!--    person的cat属性和dog属性都没有赋值,将使用自动装配-->
    <bean id="person" class="com.plane.pojo.Person">
        <property name="name" value="红猪"></property>
    </bean>

</beans>

5.spring注解开发

@Configuration使用在一个类上,假定这个类是AppConfig,则AppConfig类就相当于<beans><bean>标签了。通过new AnnotationConfigApplicationContext(AppConfig.class)获得一个context,然后就可以通过context获得bean了
@Bean使用在Appconfig的一个方法上,这个方法就相当于一个被注册的bean了。方法的返回类型相当于bean的class,方法名相当于bean的id。
@Component 这个注解用在类上,相当于把这个类注册成了一个bean。在spring中,一般使用mvc三层架构,@Component注解也多出来了几个衍生注解---->dao(@Repository), service(@Service), controller(@Controller)。 

注意一点,在使用Spring注解开发的时候,需要在配置文件中声明注解支持

    <!--扫描包下的注解-->
    <context:component-scan base-package="com.plane"></context:component-scan>
    <!--开启注解支持-->
    <context:annotation-config/>

最佳实践:关于在spring中使用配置文件和还是使用注解开发,一般会使用配置文件来获得bean,使用注解来是属性的注入。

6. aop

aop,也就是切面编程。例如,service层调用dao层业务的时候,需要输出调试信息,但是又不想改变已有的代码,这个时候就可以增加一个代理层,代理层调用dao层的相应业务并且输出调试信息,service层不再调用dao层的业务而是调用代理层的业务就好了。

形象地说,aop就相当于在一个垂直的业务结构中,横向地插入了一个业务,且不影响已有的代码。

这一章会讲解spring实现aop的三种方式:Java api实现aop、自定义代理类实现aop以及注解实现aop

6.1java api实现aop

如下,实现UserService接口和实现类

public interface UserService {
    public void add();
    public void delete();
    public void query();
    public void update();
}
public class UserServiceImpl implements UserService{
    public void add() {
        System.out.println("增加了一个用户");
    }

    public void delete() {
        System.out.println("删除了一个用户");
    }

    public void query() {
        System.out.println("查询了用户");
    }

    public void update() {
        System.out.println("修改 了用户");
    }
}

定义实现Java api接口的代理类:MethodBeforeAdvice和AfterReturningAdvice都是Java内的接口

public class BeforeLog implements MethodBeforeAdvice {
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("执行了"+method.getName()+",对象是"+target.getClass().getName());
    }
}
public class AfterLog implements AfterReturningAdvice {
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("执行了"+ method.getName()+"方法, 返回了"+returnValue);
    }
}

 配置文件如下

<?xml version="1.0" encoding="UTF-8"?>
<!--beans里面引入了使用aop的依赖-->
<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="userService" class="com.plane.service.UserServiceImpl"></bean>
    <bean id="beforeLog" class="BeforeLog"></bean>
    <bean id="afterLog" class="AfterLog"></bean>

<!--   方式一 java api 实现aop-->
    <aop:config>
<!--     定义切入点                            execution(返回类型, 包名, 类名, 方法名, 方法参数列表)        -->
        <aop:pointcut id="point" expression="execution(* com.plane.service.UserServiceImpl.*(..))"/>
<!--     进行环绕增强-->
        <aop:advisor advice-ref="beforeLog" pointcut-ref="point"></aop:advisor>
        <aop:advisor advice-ref="afterLog" pointcut-ref="point"></aop:advisor>
    </aop:config>


</beans>

测试代码及结果

        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//                           aop的原理就是动态代理,在动态代理中,代理的是接口,所以getBean方法的第二个参数是接口的类型
        UserService userService =  context.getBean("userService", UserService.class);
        userService.add();

 执行了add,对象是com.plane.service.UserServiceImpl
增加了一个用户
执行了add方法, 返回了null

6.2自定义代理类实现aop

自定义一个代理类

public class MyLog {
    public void before(){
        System.out.println("=============方法执行前=============");
    }

    public void after(){
        System.out.println("=============方法执行后=============");
    }
}

配置文件相关代码

<!--   方式二:自定义类实现aop -->
    <bean id="myLog" class="com.plane.MyLog"></bean>
    <aop:config>
<!--        定义一个切面-->
        <aop:aspect ref="myLog">
<!--        通知:在哪里切入    -->
            <aop:pointcut id="point" expression="execution(* com.plane.service.UserServiceImpl.*(..))"/>
<!--        什么时候切入    -->
            <aop:after method="after" pointcut-ref="point"></aop:after>
            <aop:before method="before" pointcut-ref="point"></aop:before>
        </aop:aspect>
    </aop:config>

测试结果

 =============方法执行前=============
增加了一个用户
=============方法执行后=============

 6.3注解实现aop

自定义一个代理类,并加上注解

//将当前类声明为一个切面
@Aspect
public class MyAspect {
    @Before("execution(* com.plane.service.UserServiceImpl.*(..))")
    public void before(){
        System.out.println("=============方法执行前---MyAspect============");
    }

    @After("execution(* com.plane.service.UserServiceImpl.*(..))")
    public void after(){
        System.out.println("=============方法执行后---MyAspect============");
    }
}

配置文件

<!--    方式三:注解实现aop-->
    <bean id="myAspect" class="com.plane.MyAspect"></bean>
<!--    开启注解支持-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

测试结果

 =============方法执行前---MyAspect============
增加了一个用户
=============方法执行后---MyAspect============ 

 很容易看出来,第三种方式和第二种方式几乎一样,不过是把使用配置文件改为使用注解而已。

7.Spring整合Mybatis

7.1简述

Mybatis的实现步骤是这样的:

1)定义一个实体类如User,实体类属性与数据库表中字段对应

2)定义一个Mapper接口,如UserMpper,接口中声明对数据库的操作方法

3)编写mapper.xml,如userMapper.xml,实现UserMapper接口中对数据库操作的方法

4)编写mybatis-config.xml文件,配置连接数据库的元数据,并把mapper.xml注册在里面

5)使用SqlSessionFactory类通过mybatis-config.xml文件获得SqlSession,利用SqlSesion,getMapper()方法获得UserMapper接口对象,UserMapper对象调用自己声明的对数据库进行操作

Spring的实现步骤是这样的:

1)定义一个类

2)编写applicationContext.xml文件,把定义的类注册在bean容器中

3)通过CPXMAC类获得一个ApplicationContext对象context,用context.getBean()方法获得需要 的对象

简单来说,mybatis是通过配置文件获得sqlSession对象,利用sqlSession获得定义的接口对象,接口对象调用方法对数据库进行操作。而spring则是利用配置文件获得一个context对象,用context.getBean()方法获得需要的类对象,进而进行操作。

在spring中,一切的实体对象都不再需要用户new出来了,而是通过context.getBean()方法获得。

spring整合mybatis用的也是这个思想,把需要通过new获得的mybatis对象都在spring的配置文件里注册好,然后通过spring的context.getBean()方法获取实体类对象,再用实体类的方法对数据库进行操作。接下来进行项目演示

7.2spring整合mybatis演示

数据库表和实体类如下

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private int id;
    private String name;
    private String pwd;
}

编写UseMapper的接口

public interface UserMapper {
    public List<User> getUserList();
}

编写userMapper.xml文件

<mapper namespace="com.plane.mapper.UserMapper">
    <select id="getUserList" resultType="User">
        select * from user
    </select>

</mapper>

编写mybatis-config.xml文件【元数据的配置都放在spring的applicationContext.xml文件中了

<configuration>
    <settings>
        <setting name="mapUnderscoreToCamelCase" value="true"/>
        <setting name="logImpl" value="STDOUT_LOGGING"/>
    </settings>

    <typeAliases>
        <typeAlias type="com.plane.pojo.User" alias="User"></typeAlias>
    </typeAliases>

    <mappers>
        <mapper resource="UserMapper.xml"/>
    </mappers>

</configuration>

 编写applicationContext.xml文件

<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="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://localhost:3306/mybatis?serverTimezone=GMT&amp;useUnicode=true&amp;characterEncoding=utf-8&amp;allowMultiQueries=true"></property>
        <property name="username" value="root"></property>
        <property name="password" value="root"></property>
    </bean>

<!--SqlSessionFactory的注册-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <!--关联一下mybatis配置文件-->
        <property name="configLocation" value="classpath:mybatis-config.xml"></property>
    </bean>

<!--    SqlSession的注册-->
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg index="0" ref="sqlSessionFactory"></constructor-arg>
    </bean>
</beans>

这些都准备好后,就先通过applicationContext.xml获得context,再用context.getBean()获得sqlSession,sqlSession.getMapper()获得mapper, mapper调用自己的方法对数据库进行操作,具体代码如下:

    @org.junit.Test
    public void test1() throws IOException {
        
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        
        SqlSession sqlSession = context.getBean("sqlSession", SqlSession.class);
        
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList = userMapper.getUserList();
        for (User user : userList) {
            System.out.println(user);
        }
    }

 User(id=1, name=宏猪, pwd=000000)
User(id=2, name=plane, pwd=000000)
User(id=3, name=xiaoming, pwd=000000)
User(id=6, name=宏猪, pwd=000000)

8. Spring中的事务

8.1简述

事务的概念在操作数据库中特别重要,目的就是为了保证数据的原子性、一致性、隔离性和持久性。那么Spring操作数据库的时候,如果中间发生了意外,比如说一个插入和删除一条数据中间出现问题,会造成什么样的结果呢?这一章节就会讲解这个问题。

8.2测试

在这个测试中,会插入和删除一条数据,但是删除的sql语句是错误的以模拟操作出现意外的情况。

为UserMapper接口添加两个方法:add()和delete

    public int add(User user);

    public int delete(int userId);

在userMapper.xml文件中映射,delete语句写错模拟出现意外情况

    <insert id="add" parameterType="User">
        insert into user(id, name, pwd) VALUES (#{id}, #{name}, #{pwd})
    </insert>

    <delete id="delete" parameterType="int">
        deletes from user where id = #{id}
    </delete>

测试代码中插入一条数据并且删除一条数据,删除数据失败但插入数据成功,不符合acid原则 

        User user = context.getBean("user", User.class);
        user.setId(4);
        user.setName("plane");
        user.setPwd("5555555");

        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        userMapper.add(user);
        userMapper.delete(5);

8.3声明式事务

 Spring已经给我们提供了事务管理,只需要配置即可。使用声明式事务,将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。将声明式事务作为横切关注点,通过aop方法模块化。

spring 的 applicationContext.xml恩济头导入tx的约束

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

http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">

在spring 容器中注册事务

    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

配置事务通知

    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>

配置aop,织入事务

<aop:config>
   <aop:pointcut id="txPointcut" expression="execution(* com.kuang.dao.*.*(..))"/>
   <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
</aop:config>

 注意:事务的概念需要在一个方法中出现的对数据库的操做才符合

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值