Spring框架概念+实战

1.依赖注入

依赖:就是一种关系,代表了软件实体之间的联系。以表明一个软件实体,依靠另一个软件实体的规范或实现,而不能自立或自给。

原本是这么写的,耦合度太高

包结构

dao包下

UserDao
package com.example.dao;

import com.example.entity.User;

public interface UserDao {
    User selectUserById(Long id);

}

UserDaoImpl
package com.example.dao;

import com.example.entity.User;

public class UserDaoImpl implements UserDao {
    @Override
    public User selectUserById(Long id) {
        System.out.println("UserDaoImpl.selectUserById");
        return null;
    }
}

service包下

UserService
package com.example.service;

import com.example.entity.User;

public interface UserService {
    User findUserById(Long id);
}
UserServiceImpl
package com.example.service;

import com.example.dao.UserDao;
import com.example.entity.User;

public class UserServiceImpl implements UserService {
    UserDao userDao = new UserDaoImpl();

    @Override
    public User findUserById(Long id) {
        return userDao.selectUserById(id);
    }
}

entity包

User
package com.example.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private Long id;
    private String username;
    private String password;
}

Test包下

UserServiceImplTest
package com.example.service;

import com.example.entity.User;
import junit.framework.TestCase;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class UserServiceImplTest extends TestCase {
    UserService userService = new UserServiceImpl();
    @Test
    public void testFindUserById() {
        User user=userService.findUserById(1L);
        System.out.println(user);
    }
}

运行效果

纯xml方式

1.添加jar包

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>${Spring.version}</version>
    </dependency>

2.创建配置文件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">

    <!--Spring主配置文件-->
    <!--配置容器管理的Bean-->
    <bean id="userDao" class="com.example.dao.UserDaoImpl"/>

    <bean id="userService" class="com.example.service.UserServiceImpl">
        <!--引用的名称,引用的ID-->
        <property name="userDao" ref="userDao"/>
    </bean>
</beans>

applicationContext.xml文件中标签的属性不自动提示

创建两个Bean,userService中引用了userDao,所以多添加一个属性,表示引用关系

容器获取的Bean默认是单例模式,通过scope属性设置

Spring容器创建bean的使用调用的是类的空参构造

3.在使用时,如在Test中

(1)实例化容器对象

(2)从容器中获取Bean实例

package com.example.service;

import com.example.entity.User;
import junit.framework.TestCase;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class UserServiceImplTest extends TestCase {
    UserService userService ;
    @Test
    public void testFindUserById() {
        //1.实例化容器对象
        ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
        //2.从容器中获取Bean实例
        UserService userService=(UserService) ac.getBean("userService");
        User user=userService.findUserById(1L);
        System.out.println(user);
    }
}

这里需要注意的是,这是使用set方式注入

所以要在实现类中添加set方法

package com.example.service;

import com.example.dao.UserDao;
import com.example.entity.User;

public class UserServiceImpl implements UserService {
    UserDao userDao ;
    // xml方式需要提供属性的set方法来绑定

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

    @Override
    public User findUserById(Long id) {
        return userDao.selectUserById(id);
    }
}

通过构造器的方式注入

XML+注解(annotation)

1.在相应的位置添加注解

1、@controller 控制器(注入服务)
2、@service 服务(注入dao)
3、@repository dao(实现dao访问)
4、@component (把普通pojo实例化到spring容器中,相当于配置文件中的<bean id="" class=""/>)@Component,@Service,@Controller,@Repository注解的类,并把这些类纳入进spring容器中管理。 
下面写这个是引入component的扫描组件 
<context:component-scan base-package=”com.example”>   

2.修改配置文件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"
       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-2.5.xsd">

        <!--开启注解扫描-->
    <context:component-scan base-package=" com.example"/>
</beans>

可以扫描com.example下所有带注解的部分

3.修改测试调用

package com.example.service;

import com.example.entity.User;
import junit.framework.TestCase;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

//使用spring-test测试,导入相应的包
//加载主配置文件
@ContextConfiguration("classpath:applicationContext.xml")
//使用spring的测试
@RunWith(SpringJUnit4ClassRunner.class)
public class UserServiceImplTest extends TestCase {
    //自动装配
    @Autowired
    UserService userService ;

    @Test
    public void testFindUserById() {
        User user=userService.findUserById(1L);
        System.out.println(user);
    }
}

导入spring-test包

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>${Spring.version}</version>
    </dependency>

已经导入Spring-context包但是没有出现注解

解决办法:清一下idea的缓存

java.lang.IllegalStateException: SpringJUnit4ClassRunner requires JUnit 4.12 or higher.

解决办法:

JUnit需要更高版本

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>

运行结果:

纯注解方式

1.添加配置类AppConfig

package com.example;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.test.context.ContextConfiguration;

/*
 * Spring 主配置类
 * */
//表示该类是一个spring核心配置类
@ContextConfiguration
//表示扫描包
//注意:可以通过basepackage配置扫描路径,如果不写,默认扫描该类所在的包以及子包
@ComponentScan
public class AppConfig {
}

2.修改测试类参数

package com.example.service;

import com.example.AppConfig;
import com.example.entity.User;
import junit.framework.TestCase;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

//使用spring-test测试,导入相应的包
@ContextConfiguration(classes = AppConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class UserServiceImplTest extends TestCase {
    //自动装配
    @Autowired
    UserService userService ;

    @Test
    public void testFindUserById() {
        User user=userService.findUserById(1L);
        System.out.println(user);
    }
}

运行结果:

添加一个list测试

AppConfig

package com.example;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.event.annotation.BeforeTestExecution;

import java.util.ArrayList;
import java.util.List;

/*
 * Spring 主配置类
 * */
//表示该类是一个spring核心配置类
@ContextConfiguration
//表示扫描包
//注意:可以通过basepackage配置扫描路径,如果不写,默认扫描该类所在的包以及子包
@ComponentScan
public class AppConfig {
    
    @Bean
    public List<String> list() {
        List<String> list = new ArrayList<>();
        list.add("AA");
        list.add("BB");
        list.add("CC");
        return list;
    }
}

测试类

package com.example.service;

import com.example.AppConfig;
import com.example.entity.User;
import junit.framework.TestCase;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import java.util.List;

//使用spring-test测试,导入相应的包
@ContextConfiguration(classes = AppConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class UserServiceImplTest extends TestCase {
    //自动装配
    @Autowired
    UserService userService ;

    @Autowired
    List<String> list;
    @Test
    public void testFindUserById() {
        User user=userService.findUserById(1L);
        System.out.println(user);
    }

    @Test
    public void listTest(){
        list.forEach(System.out::println);
    }
}

运行结果

2.AOP面向切面编程

目的是为了更高效的代码复用

问题有很多方法的时候,实现类需要重复写非核心代码

Execution

XML方式

1.添加包

   <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aspects</artifactId>
      <version>${Spring.version}</version>
    </dependency>

2.创建通知类,共性逻辑代码

package com.example.advice;

import org.aspectj.lang.JoinPoint;

import java.util.Date;

/*
* Advice通知
* */
public class LogAdvice {
    //jp对象是现场信息的封装
    public void log(JoinPoint jp) {
        //获取切入目标的方法名
        String methodName = jp.getSignature().getName();
        //获取切入目标的类名
        String className = jp.getTarget().getClass().getName();
        System.out.println(className+"类的"+methodName+"运行了,on:"+new Date());
    }
}
package com.example.advice;

import org.aspectj.lang.JoinPoint;

import java.util.Date;

/*
 * Advice通知
 * */
public class PermissionAdvice {
    public void check(JoinPoint jp) {
        //获取切入目标的方法名
        String methodName = jp.getSignature().getName();
        //获取切入目标的类名
        String className = jp.getTarget().getClass().getName();
        System.out.println(className+"类的"+methodName+"运行了,on:"+new Date());
    }
}

3.修改配置文件

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

    <!--配置被切组件-->
    <bean id="userDao" class="com.example.dao.UserDaoImpl"/>

    <bean id="userService" class="com.example.service.UserServiceImpl">
        <!--引用的名称,引用的ID-->
        <property name="userDao" ref="userDao"/>
    </bean>

    <!--配置通知-->
    <bean id="logAdvice" class="com.example.advice.LogAdvice"/>
    <bean id="permissionAdvice" class="com.example.advice.PermissionAdvice"/>

    <!--配置切面-->
    <aop:config>
        <aop:aspect ref="permissionAdvice">
            <!--配置切点表达式execution-->
            <aop:before method="check" pointcut="execution(* com.example..*ServiceImpl.find*(..))"/>
        </aop:aspect>
    </aop:config>

</beans>

特别注意execution表达式,非常灵活,指定哪些方法切入

上述代码达到的目的就是,在方法中没有写权限验证的代码但是,执行的时候依然会执行,就是因为AOP切到这个方法之前执行了

运行结果

XML+注解

主要是advice添加注解

1.对应位置添加注解

UserDaoImpl @Repository
UserServiceImpl @Service
LogAdvice 
package com.example.advice;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

import java.util.Date;

/*
* Advice通知
* */
@Component
//注解配置切面
@Aspect
public class LogAdvice {
    //jp对象是现场信息的封装
    @After("execution(* com.example..*ServiceImpl.find*(..))")
    public void log(JoinPoint jp) {
        //获取切入目标的方法名
        String methodName = jp.getSignature().getName();
        //获取切入目标的类名
        String className = jp.getTarget().getClass().getName();
        System.out.println(className+"类的"+methodName+"运行了,on:"+new Date());
        System.out.println("日志记录");
    }
}
PermissionAdvice
package com.example.advice;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

import java.util.Date;

/*
 * Advice通知
 * */
@Component
@Aspect
public class PermissionAdvice {
    @Before("execution(* com.example..*ServiceImpl.find*(..))")
    public void check(JoinPoint jp) {
        //获取切入目标的方法名
        String methodName = jp.getSignature().getName();
        //获取切入目标的类名
        String className = jp.getTarget().getClass().getName();
        System.out.println(className+"类的"+methodName+"运行了,on:"+new Date());
        System.out.println("权限验证中...");
    }
}

2.修改配置文件

<?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"
       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/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context-2.5.xsd">

    <!--开启注解扫描-->
    <context:component-scan base-package=" com.example"/>
    <!--开启AOP-->
    <aop:aspectj-autoproxy/>

</beans>

3.修改测试文件

package com.example.service;

import com.example.entity.User;
import junit.framework.TestCase;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@ContextConfiguration("classpath:applicationContext.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class UserServiceImplTest extends TestCase {
    @Autowired
    UserService userService;

    @Test
    public void testFindUserById() {
        User user = userService.findById(1L);
        System.out.println(user);
    }
}

运行结果

纯注解方式

1.添加主配置类

package com.example;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.test.context.ContextConfiguration;
//spring主配置文件类
@ContextConfiguration
//扫描注解
@ComponentScan
//开启AOP
@EnableAspectJAutoProxy
public class AppConfig {
}

2.修改测试类

package com.example.service;

import com.example.AppConfig;
import com.example.entity.User;
import junit.framework.TestCase;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@ContextConfiguration(classes= AppConfig.class)
@RunWith(SpringJUnit4ClassRunner.class)
public class UserServiceImplTest extends TestCase {
    @Autowired
    UserService userService;

    @Test
    public void testFindUserById() {
        User user = userService.findById(1L);
        System.out.println(user);
    }
}

运行结果

 

3.声明式事务

事务四大特性:ACID

编程式事务:代码写死事务边界

声明式事务:动态确定事务边界

Propagation(传播行为)

被定义了声明式事务的方法,有权知道当前是否有事务开启,并有权决定是否加入当前事务。某个方法增加到当前事务,相当于事务被传播了。传播的实质,也就是对事务的边界,在程序运行期间动态地进行控制。

配置声明式事务管理器

spring由于需要为多种数据层的实现提供集成支持,针对不同的情况,定义了各种事务管理器,一定要选择正确的事务管理器

如:对应JDBC事务,对应Hibernate提供的事务,对应JTA事务

备注:大多数事务管理器需要设置dataSource属性或sessionFactory属性

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值