栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring核心概念及入门(详细)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring核心概念及入门(详细)

文章目录
  • Spring核心概念及入门
    • 1 IOC控制反转
      • 1) Spring快速理解IOC如何解耦合
        • 1.1 创建maven项目,导入spring-context和junit的jar包
        • 1.2 创建EmpDao接口及其实现类
        • 1.3 创建Spring的核心配置文件
        • 1.4 编写对应测试类
      • 2)IOC实现原理及相关操作
        • 2.1 基于XML方式的Bean管理
        • 2.2 Spring_bean的生命周期(***)
        • 2.3 Spring读取外部属性配置文件
      • 3)Spring基于注解方式开发IOC
      • 4)Spring基于注解方式开发DI
    • 2 AOP面向切面编程
      • 2.1 代理模式
        • 2.1.1 静态代理
        • 2.1.2 动态代理(策略模式)
      • 2.2 AOP概念及代码实现

Spring核心概念及入门 1 IOC控制反转

DI是IOC的一种实现;Spring的IOC容器类似于Map,K是id,Value是class的全路径(方便后面反射)

1) Spring快速理解IOC如何解耦合 1.1 创建maven项目,导入spring-context和junit的jar包

spring的核心主要有四大模块:
spring-context 上下文,容器
spring-beans 创建对象
spring-core 核心jar
spring-expression 表达式jar
因为spring-context导入之后会进行依赖传递,其他jar包也会自动导入,因此只需要导入spring-context


    
        junit
        junit
        4.13.2
        test
    
    
        org.springframework
        spring-context
        5.3.5
    

1.2 创建EmpDao接口及其实现类

EmpDao接口:

public interface EmpDao {
    void addEmp();
}

EmpDao实现类:

public class EmpDaoImpl implements EmpDao {
    @Override
    public void addEmp() {
        System.out.println("empDaoImpl method invoked...");
    }
}
1.3 创建Spring的核心配置文件

将empDao的实现类注册到IOC容器中
Map 后面根据id找到对应的class,根据反射创建出对应的类




    

1.4 编写对应测试类
public class Test01 {

    @Test
    public void testGetBean(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        EmpDao empDao = (EmpDao) applicationContext.getBean("empDao");
        empDao.addEmp();
        //测试结果:
        //empDaoImpl method invoked...
    }
}

假设:现在有一个新的empDao实现类EmpDaoImpl2,我们需要使用它:
此时我们只需要修改Spring的配置文件即可




    

对应的测试代码不变:

public class Test01 {

    @Test
    public void testGetBean(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        EmpDao empDao = (EmpDao) applicationContext.getBean("empDao");
        empDao.addEmp();
        //addEmp2 method invoked...
    }
}
  • 极大的降低了代码间的耦合度
2)IOC实现原理及相关操作

①通过XML解析技术读取配置文件


将上面的信息读取到程序,一个是对象id,一个是对象的类的全路径名

②通过反射实例化对象,将对象放到容器中
Class clazz = Class.forName(“com.zi.dao.impl.EmpDaoImpl”);//通过字节码实例化对象
Object obj = clazz.newInstance();
//将对象放到map集合中
map.put(“empDdao”, obj);

③通过工厂模式返回Bean对象
public Object getBean(String name){
    Object obj = map.get(name);
    return obj;
}

IOC的相关接口
BeanFactory接口 : IOC容器的基本功能接口,是Spring内部使用
ApplicationContext接口: BeanFactory的子接口,提供了更多更强大的功能,研发人员一般使用的

  • 相关体系结构图:

ApplicationContext结构图:

BeanFactory体系结构图:

Spring给我们提供了两种管理Bean的方式:XML和基于注解

2.1 基于XML方式的Bean管理

  • lazy-init:是否是懒加载,默认是false,没有获取bean的时候依然初始化bean对象
  • scope:设置bean的范围;包括singleton、prototype、request、session、global session

1)使用property给类中属性赋值:

其中的name字段也可以替换为index,index表明参数位置


    
    
    
    

2)使用constructor-arg给属性赋值(通过带参构造)


    
    
    

3)通过p、c命名空间给简化给属性赋值



    


4)给属性赋null值及特殊符号


    
        
            
        
    

    
    
        >">
    

    
        
            fjasd&fda]]]>
        
    

5)通过ref给属性赋引用值
创建Mouse类:

package com.zi.pojo;

import java.util.Date;

public class Mouse {
    private String name;
    private Date birthday;

    public Mouse() {
    }

    public Mouse(String name, Date birthday) {
        this.name = name;
        this.birthday = birthday;
    }

    @Override
    public String toString() {
        return "Mouse{" +
                "name='" + name + ''' +
                ", birthday=" + birthday +
                '}';
    }

    public String getName() {
        return name;
    }

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

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }
}

通过ref给birthday属性赋值:



    
    

6)Spring中factory的运用(工厂模式)

创建Book类

package com.zi.pojo;

public class Book {
    private String name;
    private Double price;

    public Book() {
    }

    public Book(String name, Double price) {
        this.name = name;
        this.price = price;
    }

    @Override
    public String toString() {
        return "Book{" +
                "name='" + name + ''' +
                ", price=" + price +
                '}';
    }

    public String getName() {
        return name;
    }

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

    public Double getPrice() {
        return price;
    }

    public void setPrice(Double price) {
        this.price = price;
    }
}

创建BookFactory

package com.zi.pojo;

import org.springframework.beans.factory.FactoryBean;

public class BookFactory implements FactoryBean {
    @Override
    public Book getObject() throws Exception {
        Book book = new Book();
        book.setName("控球后卫修炼之道");
        book.setPrice(60.0);
        return book;
    }

    @Override
    public Class getObjectType() {
        return null;
    }
}

applicationContext.xml:Spring的核心配置文件




    
	

测试类:

public class Test03 {
    @Test
    public void test01(){
     ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext3.xml");
        Book book = applicationContext.getBean("book", Book.class);
        System.out.println(book);
    }
}

运行结果:

Book{name=‘控球后卫修炼之道’, price=60.0}

2.2 Spring_bean的生命周期(***)
  1. 构造方法
  2. set方法(注入属性)
  3. 初始化前
  4. 初始化
  5. 初始化后
  6. 使用
  7. 销毁
  • 验证:

①创建类User类:

package com.zi.pojo;


public class User {
    private Integer userid;
    private String username;
    private String password;

    @Override
    public String toString() {
        return "User{" +
                "userid=" + userid +
                ", username='" + username + ''' +
                ", password='" + password + ''' +
                '}';
    }

    public void init(){
        System.out.println("第三步:User初始化");
    }

    public void destroy(){
        System.out.println("第五步:User销毁");
    }

    public User() {
        System.out.println("第一步:User构造");
    }

    public User(Integer userid, String username, String password) {
        System.out.println("allArgConstructor");
        this.userid = userid;
        this.username = username;
        this.password = password;
    }

    public void setUserid(Integer userid) {
        System.out.println("setUserid");
        this.userid = userid;
    }

    public void setUsername(String username) {
        System.out.println("第二步:User属性赋值");
        this.username = username;
    }

    public void setPassword(String password) {
        System.out.println("setpassword");
        this.password = password;
    }
}


②创建MyBeanPostProcessor后置处理器:

package com.zi.pojo;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

public class MyPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("bean初始化方法之前.....");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("bean初始化方法之后....");
        return bean;
    }
}

③创建Spring核心配置文件(将自定义后置处理器注册到IOC容器中)




    
        
    

    


④测试

package com.zi.test;

import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test04 {
    @Test
    public void test01(){
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext4.xml");

        System.out.println("第四步:使用User");
        applicationContext.close();
    }
}

测试结果:

第一步:User构造
第二步:User属性赋值
bean初始化方法之前…
第三步:User初始化
bean初始化方法之后…
第四步:使用User
第五步:User销毁

2.3 Spring读取外部属性配置文件

此处以读取数据库连接信息为例

①导入jar包


     com.alibaba
     druid
     1.2.6
 
 
     mysql
     mysql-connector-java
     8.0.28
 

②编写jdbc.properties配置文件

jdbc.driver=com.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mq?serverTimeZone=UTC
jdbc.username=root
jdbc.password=200151

③在Spring核心配置文件applicationContext.xml中配置相关bean

注意引入context命名空间



	
    

    
        
        
        
        
    

④测试

public class Test05 {

    @Test
    public void test(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext5.xml");
        DruidDataSource dataSource = applicationContext.getBean("dataSource", DruidDataSource.class);
        System.out.println(dataSource);
    }
    
}
3)Spring基于注解方式开发IOC

注意:在使用注解开发前,必须要导入spring-aop.jar
但是由于是maven开发,会自动帮助我们导入依赖包,因此只需要导入spring-context即可

①导入jar包:



    4.0.0

    org.example
    spring_test-03
    1.0-SNAPSHOT

    
        8
        8
    

    
        
            
                org.apache.maven.plugins
                maven-compiler-plugin
                3.8.1
                
                    8
                    8
                
            
        
    

    
        
            org.springframework
            spring-context
            5.3.21
        

        
            junit
            junit
            4.13.2
            test
        
    

②创建类,并加上对应注解

注解表示含义
@Component普通bean
@Serviceservice层的bean
@Repositorydao层的bean
@Controllercontroller层的bean
package com.zi.pojo;

import org.springframework.stereotype.Component;

@Component
public class User {
    private String username;
    private Integer age;


    public User() {
    }

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + ''' +
                ", age=" + age +
                '}';
    }

    public User(String username, Integer age) {
        this.username = username;
        this.age = age;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}

③创建配置文件applicationContext.xml,并扫描对应包【注意引入context名称空间】




    

拓展:
1 配置只扫描加了@Controller的类




    
        
        
    

2 配置除了加了@Service注解的类,其他加了注解的类都扫描
【记得开启默认过滤器】




    
        
    

3 @Bean与@Component

@Bean
public User getUser(){
    return new User();
}
@Component
public class User{
}
4)Spring基于注解方式开发DI
注解作用
@Autowired自动注入
@Qualifier标识,当有多个实现类时搭配@Autowired使用
@Value给属性赋值
@Resource自动注入(jdk提供的)

@Autowired + @Qualifier = @Resource(name = “”)
@Resource()是jdk里面提供的

【1】@Autowired+@Qualifier用法:
UserDaoImplA:

@Repository
public class UserDaoImplA implements UserDao {
    @Override
    public void addUer() {
        System.out.println("userDaoImplA method run ...");
    }
}

UserDaoImplB:

@Repository
public class UserDaoImplB implements UserDao {
    @Override
    public void addUer() {
        System.out.println("userDaoImplB method run ...");
    }
}

UserService:

@Service
public class UserService {

    @Qualifier("userDaoImplA")
    @Autowired
    private UserDao userDao;

    public void addUser(){
        System.out.println("userService method run...");
        userDao.addUer();
    }
}

测试类:

public class Test01 {

    @Test
    public void test01(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService userService = applicationContext.getBean("userService", UserService.class);
        userService.addUser();
        //userService method run...
        //userDaoImplA method run ...
    }
}

【2】@Value的用法:
data.properties:

name=curry
age=25

applicationContext.xml:




    

    

使用:

@Component
public class User {
    @Value("${name}")
    private String username;
    @Value("${age}")
    private Integer age;
}

拓展:在开发中我们可以舍弃applicationContext.xml配置文件,转用全注解开发。但是不推荐

【3】全注解开发:
SpringConfig配置类:

@ComponentScan(basePackages = "com.zi")
@PropertySource("classpath:data.properties")
public class SpringConfig {
}

User类:

@Component
public class User {
    @Value("${name}")
    private String username;
    @Value("${age}")
    private Integer age;
}

外部资源类data.properties:

name=curry
age=25

测试类:

@Test
public void test03(){
    ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
    User user = applicationContext.getBean("user", User.class);
    System.out.println(user);
}
2 AOP面向切面编程
  • 前置知识:代理模式【中间商、找帮手】
    • 动态代理
    • 静态代理
2.1 代理模式 2.1.1 静态代理

静态代理:代理类与被代理类都实现相同接口

代码演示:

package com.zi.test;

import org.junit.Test;

public class Test01 {

    @Test
    public void test01(){
        Person p = new Person("法外狂徒张三");
        Layer layer = new Layer(p);
        layer.doCourt();
        //律师说:我有视频,视频表明法外狂徒张三有不在场证明
        //律师说:法外狂徒张三是无罪的
        //法外狂徒张三说:我是无罪的
    }

}


interface Court{
    //打官司
    void doCourt();
}

class Person implements Court{
    private String name;

    public Person(){
    }

    public Person(String name){
        this.name = name;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public void doCourt() {
        System.out.println(name+"说:我是无罪的");
    }
}

class Layer implements Court{
    public Layer(Person person){
        this.person = person;
    }
    private Person person;

    @Override
    public void doCourt() {
        System.out.println("律师说:我有视频,视频表明"+person.getName()+"有不在场证明");
        System.out.println("律师说:"+person.getName()+"是无罪的");
        person.doCourt();
    }
}
2.1.2 动态代理(策略模式)

Proxy:动态代理 JDK动态代理 基于接口
Cglib: 动态代理 第三方 基于父类

①Proxy(JDK动态代理:基于接口,InvocationHandler)

通过JDK的Proxy动态代理,实现对某个特定方法进行增强

package com.zi.test;

import org.junit.Test;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;


public class Test02 {

    @Test
    public void test() {
        Dinner dinner = new Person("张三");

        ClassLoader classLoader = dinner.getClass().getClassLoader();
        Class[] interfaces = dinner.getClass().getInterfaces();

        InvocationHandler invocationHandler = new InvocationHandler() {
            
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                Object res = null;
                if (method.getName().equals("eat")) {
                    System.out.println("饭前洗手...");
                    res = method.invoke(dinner, args);
                    System.out.println("饭后看球赛...");
                } else {
                    res = method.invoke(dinner, args);
                }
                return res;
            }
        };
        Dinner dinnerProxy = (Dinner) Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);

//        dinnerProxy.eat("小龙虾");
        dinnerProxy.drink();
    }

}


interface Dinner {
    void eat(String foodName);

    void drink();
}

class Student implements Dinner {
    private String name;

    public Student(String name) {
        this.name = name;
    }

    public Student() {
    }

    @Override
    public void eat(String foodName) {
        System.out.println(name + "晚上吃:" + foodName);
    }

    @Override
    public void drink() {
        System.out.println(name + "喝:" + "凉白开");
    }
}

class Person implements Dinner {
    public Person(String name) {
        this.name = name;
    }

    public Person() {
    }

    private String name;

    @Override
    public void eat(String foodName) {
        System.out.println(name + "晚上吃:" + foodName);
    }

    @Override
    public void drink() {
        System.out.println(name + "喝普洱茶");
    }
}

②CGLib动态代理(基于父类)

使用之前需要有spring-core包,根据maven依赖传递自动导入,只需导入spring-context包

package com.zi.test;

import org.junit.Test;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;


public class Test03 {

    @Test
    public void testCGLib(){
        Person p = new Person();
        // 1 获取Enhancer对象
        Enhancer enhancer = new Enhancer();
        // 2 设置父类字节码
        enhancer.setSuperclass(Person.class);
        // 3 获取MethodInterceptor对象 用于增强规则
        MethodInterceptor methodInterceptor = new MethodInterceptor() {
            
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                Object res = null;
                if(method.getName().equals("eat")){
                    System.out.println("饭前要洗手...");
                    res = methodProxy.invokeSuper(o, objects);
                    System.out.println("饭后看球赛...");
                }else{
                    res = methodProxy.invokeSuper(o, objects);
                }
                return res;
            }
        };
        // 4 设置methodInterceptor
        enhancer.setCallback(methodInterceptor);
        // 5 获得代理对象
        Person personProxy = (Person) enhancer.create();
        // 6 使用代理对象完成功能
//        personProxy.drink();
        personProxy.eat("小龙虾");
        //饭前要洗手...
        //张三正在吃:小龙虾
        //饭后看球赛...
    }
}
class Person{
    public void eat(String foodName){
        System.out.println("张三正在吃:" + foodName);
    }
    public void drink(){
        System.out.println("张三正在喝凉白开...");
    }
}


2.2 AOP概念及代码实现

AOP的实现有JDK动态代理和CGLib动态代理
AOP作用:日志处理,权限控制,性能检测,事务控制等

AOP术语含义
连接点(Joincut)可以被增强的方法(候选人)
切入点(Pointcut)被增强的方法
通知(Advice)增强的功能
目标对象(target)被代理对象
切面(Aspect)advice方法放在一起声明为一个Java类
织入(Waving)创建代理对象实现功能增强并运行的过程

通知:前置、后置、环绕、异常、最终通知

代码实现:
①创建maven工程,导入jar包
核心包:spring-context、aopalliance、spring-aspects



    4.0.0

    org.example
    spring_aop_02
    1.0-SNAPSHOT
    
        
            
                org.apache.maven.plugins
                maven-compiler-plugin
                3.8.1
                
                    8
                    8
                
            
        
    

    
        8
        8
    

    
        
            org.springframework
            spring-context
            5.3.21
        

        
        
            org.springframework
            spring-aspects
            5.3.16
        

        
        
            aopalliance
            aopalliance
            1.0
        

        
            commons-logging
            commons-logging
            1.2
        

        
            junit
            junit
            4.13.2
            test
        

    

②创建Dao层:
UserDao:

public interface UserDao {
    int addUser(Integer uid, String uname);
}

EmpDao:

public interface EmpDao {
    int addEmp(Integer empno, String name, String job);
}

UserDaoImpl:

import com.zi.dao.UserDao;
import org.springframework.stereotype.Repository;

@Repository
public class UserDaoImpl implements UserDao {

    @Override
    public int addUser(Integer uid, String uname) {
        System.out.println("addUser... ...");
        return 1;
    }
}

EmpDaoImpl:

import com.zi.dao.EmpDao;
import org.springframework.stereotype.Repository;

@Repository
public class EmpDaoImpl implements EmpDao {
    @Override
    public int addEmp(Integer empno, String name, String job) {
        System.out.println("addEmp ... ...");
//        int res = 2 / 0;
        return 1;
    }
}

③定义切面类,定义增强功能:

package com.zi.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.Arrays;

@Aspect
@Component
public class UserAspect {

    //定义公共切点
    @Pointcut("execution(* com.zi.dao.*.add*(..))")
    public void addPointcut(){}

    //定义前置通知
    @Before("addPointcut()")
    public void methodBefore(JoinPoint joinPoint){
        Object[] args = joinPoint.getArgs();
        System.out.println(Arrays.toString(args));
        System.out.println("methodBefore invoked ... ...");
    }

    //定义后置通知
    @After("addPointcut()")
    public void methodAfter(){
        System.out.println("methodAfter invoked...");
    }

    //定义返回通知
    @AfterReturning("addPointcut()")
    public void methodAfterReturning(){
        System.out.println("methodAfter Returning invoked...");
    }

   
    @AfterThrowing(value = "addPointcut()", throwing = "ex")
    public void methodAfterThrowing(Exception ex){
        System.out.println("methodAfter Throwing invoked...");
    }

       

    @Around("addPointcut()")
    public Object methodAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("aroundA invoked...");
        Object proceed = proceedingJoinPoint.proceed();
        System.out.println("aroundB invoked...");
        return proceed;
    }
}

④测试:

package com.zi.test;

import com.zi.dao.EmpDao;
import com.zi.dao.UserDao;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test01 {
    @Test
    public void test(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//        UserDao userDao = applicationContext.getBean(UserDao.class);
//        userDao.addUser(1, "liu");
//        System.out.println(row);
        EmpDao empDao = applicationContext.getBean(EmpDao.class);
        empDao.addEmp(20,"Jack","Manager");
        
    }
}

拓展:
其中可以用配置类替换applicationContext.xml:

@Configuration @ComponentScan("com.zi") @EnableAspectJAutoProxy(proxyTargetClass = true) public class SpringConfig { }

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1014457.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号