Spring

Spring

Spring是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架。

所谓的 IOC,即对象由Spring来创建、管理、装配,IOC 实现方式是依赖注入 DI

Spring默认创建对象,是在创建Spring容器时,会创建配置文件中所有的对象,默认调用有参构造

IOC创建对象

IOC 默认使用 无参构造函数 创建对象,但也可以使用有参构造器:

  • 通过下标赋值

<bean id="hello" class="com.wang.pojo.Hello">
    <constructor-arg index="0" value="王"/>
</bean>
  • 通过类型赋值

<bean id="hello" class="com.wang.pojo.Hello">
    <constructor-arg type="java.lang.String" value="王"/>
</bean>
  • 通过参数名称赋值

<bean id="hello" class="com.wang.pojo.Hello">
    <constructor-arg name="str" value="李"/>
</bean>

配置文件加载时,容器中管理的对象已经初始化了

配置说明

alias

<alias name="hi" alias="sdskdjsnfdjn"/>

bean

// id为对象名,class为全类名,name为别名,可取多个
<bean id="hi" class="com.wang.pojo.Hello" name="hi2 h3,h4;h5">
    <property name="str" value="li"/>
</bean>-->

import

// 可将多个配置文件合并为一个
<import resource="beans1.xml"/>
<import resource="beans2.xml"/>

DI 依赖注入

  1. 构造器注入 (见 IOC 创建对象)

  2. set方式注入(属性注入)

    依赖:bean对象的创建依赖于容器! 注入:bean对象中的所有属性,由容器来注入!

  3. 拓展方式注入:

    p命名空间注入(属性):需要在xml头部添加:xmlns:p="http://www.springframework.org/schema/p",本质为set注入,需要无参构造和set方法

    c命名空间注入(构造):需要在xml头部添加:xmlns:p="http://www.springframework.org/schema/c",本质为构造器注入,需要有参构造

public class Student {
    private String name;
    private Address address;
    private String[] books;
    private List<String> hobbies;
    private Map<String,String> card;
    private Set<String> games;
    private Properties info;
    private String wife;
}
​
public class Address {
    private String address;
}

set 注入:

<bean id="address" class="com.wang.pojo.Address">
    <property name="address" value="南京"/>
</bean>
​
<bean id="student" class="com.wang.pojo.Student">
    <property name="name" value="王"/>
    <!-- Bean注入,ref -->
    <property name="address" ref="address"/>
    <!-- 数组注入,array -->
    <property name="books">
        <array>
            <value>红楼梦</value>
            <value>西游记</value>
            <value>水浒传</value>
        </array>
    </property>
    <!-- List注入,list -->
    <property name="hobbies">
        <list>
            <value>听歌</value>
            <value>看电影</value>
            <value>敲代码</value>
        </list>
    </property>
    <!-- Map注入,map -->
    <property name="card">
        <map>
            <entry key="身份证" value="123456"/>
            <entry key="银行卡" value="654321"/>
        </map>
    </property>
    <!-- Set注入,set -->
    <property name="games">
        <set>
            <value>LOL</value>
            <value>BOB</value>
        </set>
    </property>
    <!-- Null注入,null -->
    <property name="wife">
        <value>null</value>
        <!--<null/>-->
    </property>
    <!-- Properties注入,Properties -->
    <property name="info">
        <props>
            <prop key="学号">123</prop>
            <prop key="姓名">张三</prop>
        </props>
    </property>
</bean>

自动装配

默认单例模式(singleton),还有原型模式(prototype)、request、session、application、webSocket

隐式的自动装配Bean,自动装配是Spring满足bean依赖的一种方式!

byName 会自动在上下文查找,和自己对象set方法后面的值对应的 bean_id,需要保证所有bean的id唯一

byType 会自动在上下文查找,和自己对象属性类型相同的 bean,需要保证所有bean的class唯一

<bean id="cat" class="com.wang.pojo.Cat"/>
<bean id="dog" class="com.wang.pojo.Dog"/>
<bean id="people" class="com.wang.pojo.People" autowire="byName">
    <property name="name" value="小王"/>
    <!--        <property name="cat" ref="cat"/>-->
    <!--        <property name="dog" ref="dog"/>-->
</bean>

注解实现自动装配

在 xml 中添加 context 网址 及 < context:annotation-config /> 开启自动装配,并在实体类 People 中的 Cat 类和 Dog 类加上注解,且 People 类中可省略 set 方法,前提是自动装配的属性在 IOC 容器中存在,且符合类型byType!

@Autowired(required = false) 说明这个对象可为null,否则不允许为空,或者使用 @Nullable 注解

<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
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
​
    <context:annotation-config/>
​
    <bean id="cat" class="com.wang.pojo.Cat"/>
    <bean id="dog" class="com.wang.pojo.Dog"/>
    <bean id="people" class="com.wang.pojo.People"/>
</beans>
public class People {
    @Autowired
    private Dog dog;
    @Autowired
    private Cat cat;
    private String name;
}

@Autowired 先根据 byType 进行注入,如果容器中有多个满足类型的实例,就会根据 byName 进行注入,并不是单纯只根据类型注入,@Resource 默认按照 byName 实现,找不到名字再通过 byType 实现

@Autowired
@Qualifier(value = "cat1")
private Cat cat;
​
<bean id="cat1" class="com.wang.pojo.Cat"/>

注解开发

注解开发必须导入 aop 包,导入 context 约束, 增加注解的支持

<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
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">
​
    <context:component-scan base-package="com.wang.pojo"/>
    <context:annotation-config/>
</beans>

自动装配注解

@Autowired:自动装配通过 Type,然后 Name,若属性不唯一,可搭配 @Qualifier (value = "xxx")

@Nullable:允许该属性为 Null 空值

@Resource:自动装配通过 Name,然后 Type

衍生注解:

pojo 中 @Component

dao 中 @Repository

service 中 @Service

controller 中 @Controller

上述四个注解代表将 某个类 注册到 Spring 中,装配 bean,只需要在 xml 中配置:

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

作用域注解:@Scope("singleton")

属性赋值:@Value("王")

用java配置Spring

  1. 编写 java 文件,添加 @Configuration 注解 和 @Bean 注解,Configuration 本质是一个 Component

    package com.wang.config;
    ​
    import com.wang.pojo.User;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    ​
    @Configuration
    public class MyConfig {
    ​
        @Bean
        public User getUser(){
            return new User();
        }
    }
  2. 为实体类添加 @Component 表示被 Spring 托管,@Value("xxx") 给属性赋值

    package com.wang.pojo;
    ​
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Scope;
    import org.springframework.stereotype.Component;
    ​
    @Component
    public class User {
        private String name;
    ​
        public String getName() {
            return name;
        }
    ​
        @Value("xx")
        public void setName(String name) {
            this.name = name;
        }
    }
  3. 测试类实现

    import com.wang.config.MyConfig;
    import com.wang.pojo.User;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    ​
    public class MyTest {
        public static void main(String[] args) {
            ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
            User user = (User) context.getBean("getUser");
            System.out.println(user.getName());
        }
    }
    ​

    上述不准确,有两种配置方式:1:只在类前面加 @Bean 注解,通过 getBean("getUser") 获取对象;2:在配置类前加 @Configuration 和 @ComponentScan(basePackages = "com.wang.pojo"),并且在实体类添加 @Component 注解,通过 getBean("user") 获取对象

静态代理 动态代理

动态代理:

基于接口的动态代理:JDK 动态代理

基于类的动态代理:cglib

java 字节码实现:JAVAssist

Proxy、InvocationHandler 调用处理程序

Proxy 提供创建动态代理类和实例的静态方法

InvocationHandler 处理代理实例,创建其代理的接口中相对应的方法,并返回结果

一个动态代理类代理的是一个接口,一般对应一类业务,可实现多个类的代理

package com.wang.demo1;
​
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
​
public class ProxyNew implements InvocationHandler {
    private Rent rent;
​
    public void setRent(Rent rent) {
        this.rent = rent;
    }
​
    public Object getProxy(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(), rent.getClass().getInterfaces(), this);
    }
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object invoke = method.invoke(rent, args);
        return invoke;
    }
}
​
// 主程序
package com.wang.demo1;
​
public class Client {
    public static void main(String[] args) {
        Rent rent = new Host();
//        Proxy proxy = new Proxy();
//        proxy.setHost(rent);
//        proxy.rent();
        ProxyNew proxyNew = new ProxyNew();
        proxyNew.setRent(rent);
        Rent proxy = (Rent) proxyNew.getProxy();
        proxy.rent();
    }
}

AOP

  1. 添加依赖

<dependencies>
    <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.9.8</version>
        <scope>runtime</scope>
    </dependency>
</dependencies>
  1. 编写 UserService 接口 及其 实现类 UserServiceImpl,编写 前置日志 和 后置日志 的类,如下:

package com.wang.service;

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

public class LogBefore implements MethodBeforeAdvice {

    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println(target.getClass().getName()+"的"+method.getName()+"被执行了!");
    }
}

package com.wang.service;

import org.springframework.aop.AfterReturningAdvice;

import java.lang.reflect.Method;

public class LogAfter implements AfterReturningAdvice {
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println(method.getName()+"执行完毕,返回值为"+ returnValue);
    }
}
  1. 在Spring 中配置Bean,配置 aop

execution:[访问修饰符] 方法返回值 包名.类名.方法名(方法的参数)

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

    <bean id="userService" class="com.wang.service.UserServiceImpl"/>
    <bean id="logBefore" class="com.wang.service.LogBefore"/>
    <bean id="logAfter" class="com.wang.service.LogAfter"/>

    <aop:config>
        <aop:pointcut id="pc" expression="execution(* com.wang.service.UserServiceImpl.*(..))"/>
        <aop:advisor advice-ref="logBefore" pointcut-ref="pc"/>
        <aop:advisor advice-ref="logAfter" pointcut-ref="pc"/>
    </aop:config>
</beans>

还可以自定义切面,配置 aop,自定义类需要配置Bean

package com.wang.service;

public class diy {
    public void before(){
        System.out.println("======开始======");
    }
    public void after(){
        System.out.println("======结束======");
    }
}
<bean id="diy" class="com.wang.service.diy"/>
<aop:config>
    <aop:aspect ref="diy">
        <aop:pointcut id="pc1" expression="execution(* com.wang.service.UserServiceImpl.*(..))"/>
        <aop:before method="before" pointcut-ref="pc1"/>
        <aop:after method="after" pointcut-ref="pc1"/>
    </aop:aspect>
</aop:config>

还可以直接在类上加 @Aspect,方法上加 @Before("execution(.....)") 或者 @After (切入点),只需要在 xml 中配置 Bean,以及开启注解支持 < aop:aspectj-autoproxy/ >

<aop:aspectj-autoproxy/>
<bean id="diy2" class="com.wang.service.diy2"/>
package com.wang.service;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class diy2 {
    @Before("execution(* com.wang.service.UserServiceImpl.*(..))")
    public void before(){
        System.out.println("======开始======");
    }
    @After("execution(* com.wang.service.UserServiceImpl.*(..))")
    public void after(){
        System.out.println("======结束======");
    }
    @Around("execution(* com.wang.service.UserServiceImpl.*(..))")
    public void around(ProceedingJoinPoint pj) throws Throwable {
        System.out.println("环绕前");
        System.out.println(pj.getSignature());
        pj.proceed();
        System.out.println("环绕后");
    }
}

综上,一共3种,为使用Spring的API接口实现、自定义来实现AOP(定义切面)、注解实现

整合Mybatis

建立 Spring 配置文件,配置 dataSource 和 sqlSessionFactory

<!--配置 dataSource-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&amp;characterEncoding=utf8&amp;useSSL=true"/>
    <property name="username" value="root"/>
    <property name="password" value="wzf"/>
</bean>

<!--配置 sqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="configLocation" value="classpath:mybatis-config.xml"/>
    <property name="mapperLocations" value="classpath:com/wang/mapper/*.xml"/>
</bean>

需要给接口加一个实现类,为了调用 dao 的方法,在 Spring 中 注册 sqlSession,构造函数注入 sqlSessionFactory,注册 PeopleMapper,注入sqlSession,如下所示:

public class PeopleMapperImpl implements PeopleMapper{
    private SqlSessionTemplate sqlSession;

    public void setSqlSession(SqlSessionTemplate sqlSession) {
        this.sqlSession = sqlSession;
    }

    public List<People> query() {
        PeopleMapper mapper = sqlSession.getMapper(PeopleMapper.class);
        return mapper.query();
    }
}
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
    <constructor-arg index="0" ref="sqlSessionFactory"/>
</bean>

<bean id="PeopleMapper" class="com.wang.mapper.PeopleMapperImpl">
    <property name="sqlSession" ref="sqlSession"/>
</bean>

也可以加一个实现类,在实现接口的基础上,继承父类 SqlSessionDaoSupport,这样就只需要在 Spring 中注册PeopleMapper2,并注入 sqlSessionFactory,如下:

import org.mybatis.spring.support.SqlSessionDaoSupport;

import java.util.List;

public class PeopleMapperImpl2 extends SqlSessionDaoSupport implements PeopleMapper{
    public List<People> query() {
        PeopleMapper mapper = getSqlSession().getMapper(PeopleMapper.class);
        return mapper.query();
    }
}
<bean id="PeopleMapper2" class="com.wang.mapper.PeopleMapperImpl2">
    <property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>

事务管理

声明式事务(AOP)

编程式事务 (改变原有代码)

一般用声明式事务,可以在不改变原有代码情况下实现事务,首先配置 transcationManager,再结合 AOP 实现事务的织入

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

然后配置事务通知,包括给哪些方法配置事务,配置事务的传播属性

<tx:advice id="txAdvice" transaction-manager="transcationManager">
    <tx:attributes>
        <tx:method name="query" read-only="true"/>
        <tx:method name="*" propagation="REQUIRED"/>
    </tx:attributes>
</tx:advice>

然后配置事务切入

<aop:config>
    <aop:pointcut id="txPc" expression="execution(* com.wang.mapper.*.*(..))"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="txPc"/>
</aop:config>

 

posted on 2022-03-19 18:43  木非辛  阅读(43)  评论(0)    收藏  举报