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

Spring

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

Spring

官网:https://spring.io/

自学文档:https://docs.spring.io/spring-framework/docs/current/reference/html/core.html
maven依赖


    org.springframework
    spring-webmvc
    5.3.19

组成 七大模块

IOC
  • 理论推导
  1. UserDao接口
  2. UserDaoImpl实现
  3. UserService业务接口
  4. UserService业务实现
private UserDao userDao;

// 利用set进行动态实现值的注入!
public void setUserDao(UserDao userDao) {
    this.userDao = userDao;
}
IOC创建对象方式

官方模板




      
        
    

    
        
    

    



	
	


	


    
    


    


    
    


    


    
    


    

IOC 小结好处:

  • bean单个存在,单例模式,不用担心内存泄漏问题。
  • 对象由Spring创建,管理,装配。
实例化一个容器
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Student student = context.getBean("student", Student.class);
System.out.println(student);
DI 依赖注入

    



    
    
    
        
            红楼梦
            西游记
            水浒传
            三国演义
        
    
    
        
            听歌
            看电影
            敲代码
        
    
    
        
            
            
        
    
    
        
            LOL
            COC
            BOB
        
    
    
        
    
    
        
            com.mysql.cj.jdbc.Driver
            jdbc:mysql:///mydb
            root
            root
        
    

拓展
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"





Bean别名



import元素



自动装配Bean






    



小结:

  • byName,需要保证所有bean的id唯一,并且这个bean需要和自动注入的属性的set方法一致。
  • byType,需要保证所有的bean的class唯一,并且这个bean和自动注入的类型一致。
Bean 作用域
范围描述
singleton(默认)将单个 bean 定义限定为每个 Spring IoC 容器的单个对象实例。
prototype将单个 bean 定义限定为任意数量的对象实例。
request将单个 bean 定义限定为单个 HTTP 请求的生命周期。也就是说,每个 HTTP 请求都有自己的 bean 实例,该实例是在单个 bean 定义的后面创建的。仅在 Web 感知 Spring 的上下文中有效ApplicationContext。
session将单个 bean 定义限定为 HTTP 的生命周期Session。仅在 Web 感知 Spring 的上下文中有效ApplicationContext。
application将单个 bean 定义限定为ServletContext. 仅在 Web 感知 Spring 的上下文中有效ApplicationContext。
websocket将单个 bean 定义限定为WebSocket. 仅在 Web 感知 Spring 的上下文中有效ApplicationContext。
使用注解实现自动装配
  1. 导入约束 并配置注解的支持
xmlns:context="http://www.springframework.org/schema/context"

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

  1. @Autowired
  • 一般直接在属性使用,底层通过类型反射注入
  • 使用@Autowired可以不用Set方法,前提属性在IOC容器
  • @Autowired默认根据Bean名装配 Bean名是JavaType首字母小写,如果容器找不到对应的Bean名,且JavaType没有重复,会使用类型注入,否则报错。
  • 报错
    • 找不到Bean
    • 有多个Bean同类型,只能选择一个
  1. 当给定注入点没有匹配的候选 bean 时,自动装配会失败。在声明的数组、集合或映射的情况下,至少需要一个匹配元素,也可以在参数前加@Nullable
@Autowired(required = false)
public void setMovieFinder(MovieFinder movieFinder) {
    this.movieFinder = movieFinder;
}

@Autowired
public void setMovieFinder(@Nullable MovieFinder movieFinder) {
    this.movieFinder = movieFinder;
}
  1. 使用@Autowired 容器中多个类型相同时,可以指定Bean名自动装配
@Autowired
@Qualifier("cat1")
private Cat cat;



或者用@Resource (在框架中开发中,由jdk提供,一般不用)

@Resource(name = "cat1")
private Cat cat;
private String name;
使用注解开发
  1. @Conponent 这几个注解作用一样,当前类交给spring容器管理
  • controller【@Controller】
  • service【@Service】
  • dao【@Repository】
  1. @Value 给属性赋值
  2. @Scope("singleton ") 单例, prototype多例

小结

  • xml与注解:
    • xml更加万能,适用于任何场合,维护简单方便
    • 注解不是自己类使用不了,维护相对复杂
  • xml与注解最佳实践
    • xml用来管理bean
    • 注解只负责完成属性注入
    • 使用注解需开启注解支持



  1. @Configuration 表示这是一个配置类,相当于xml

  2. @ComponentScan(“”) 包扫描

  3. @Bean 相当于bean标签,方法名相当于id元素,方法的返回值相当于class元素

通过配置类 实例化一个容器

ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
User getUser = context.getBean("getUser", User.class);
System.out.println(getUser);
  1. @Import() 相当于xml配置文件的import元素 ,参数是JavaType的class对象
静态代理

好处:

  • 可以使真实角色的操作更加纯粹,不用去关注一些公共的业务
  • 公共也就交给代理角色,实现了业务分工
  • 公共业务发生扩展的时候,方便集中管理、

缺点:

  • 一个真实角色就会产生一个代理角色;代码量会翻倍,开发效率会变低

接口

public interface UserService {
    void add();
    void delete();
    void update();
    void query();
}

实现

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

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

    @Override
    public void update() {
        System.out.println("更改了一个用户");
    }

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

代理

public class UserServiceProxy implements UserService {

    private UserServiceImpl userService;

    public void setUserService(UserServiceImpl userService) {
        this.userService = userService;
    }

    @Override
    public void add() {
        log("add");
        userService.add();
    }

    @Override
    public void delete() {
        log("delete");
        userService.delete();
    }

    @Override
    public void update() {
        log("update");
        userService.update();
    }

    @Override
    public void query() {
        log("query");
        userService.query();
    }

    //日志方法
    public void log(String msg) {
        System.out.println("【Debug】"+msg+"方法");
    }
}

测试

public class Client {
    public static void main(String[] args) {
        UserServiceImpl userService = new UserServiceImpl();

        UserServiceProxy proxy = new UserServiceProxy();
        proxy.setUserService(userService);
        proxy.add();
        proxy.delete();
        proxy.update();
        proxy.query();
    }
}
动态代理
  • 动态代理和静态代理角色一样
  • 动态代理的代理类是动态生成的,不是我们直接写好的
  • 动态代理分为两大类:基于接口的动态代理,基于类的动态代理
    • 基于接口: jdk代理 【这里使用】
    • 基于类的:cglib
    • java字节码实现:JAVAssist

需要了解两个类:Proxy,InvocationHandler

接口

public interface UserService {
    void add();
    void delete();
    void update();
    void query();
}

实现

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

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

    @Override
    public void update() {
        System.out.println("更改了一个用户");
    }

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

代理

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

public class ProxyInvocationHandler implements InvocationHandler {

    // 被代理的接口
    private Object target;

    public void setTarget(Object target) {
        this.target = target;
    }

    // 生成得到代理类
    public Object getProxy() {
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),
                target.getClass().getInterfaces(), this);
    }

    @Override
    //处理代理实例 并返回结果
    public Object invoke(Object proxy, Method method, Object[] args) throws Exception {
        // 动态代理的本质 就是反射机制实现
        log(method.getName());
        Object result = method.invoke(target, args);
        return result;
    }

    public void log(String msg) {
        System.out.println("执行了" + msg + "方法");
    }
}

测试

public class Client {
    public static void main(String[] args) {
        ProxyInvocationHandler pih = new ProxyInvocationHandler();
        pih.setTarget(new UserServiceImpl());
        UserService proxy = (UserService) pih.getProxy();
        proxy.add();
    }
}

动态代理的好处:

  • 一个动态代理类 代理的是一个接口,一般就是对应的一类业务

  • 一个动态代理类可以代理多个类,只要是实现了同一个接口即可

AOP

Maven依赖


    org.aspectj
    aspectjweaver
    1.9.4

Aop在Spring中的作用

提供声明式事务,允许用户自定义切面

  • 横切关注点:跨越应用程序多个模块的方法或功能.既是,与我们业务逻辑无关,但是我们需要关注的部分,就是横切关注点.如日志,安全,缓存,事务等等…
  • 切面(ASPECT):横切关注点 被模块化 的特殊对象。即,它是一个类。
  • 通知(Advice):切面必须要完成的工作。即,它是类中的一个方法。
  • 目标(Target):被通知对象。
  • 代理(Proxy):向目标对象应用通知之后创建的对象。
  • 切入点(PointCut):切面通知 执行的 “地点”的定义。
  • 连接点(JointPoint):与切入点匹配的执行点。

SpringAOP中,通过Advice定义横切逻辑,Spring中支持5种类型的Advice:

  • org.springframework.aop.MethodBeforeAdvice (前置通知:在方法前)
  • org.springframework.aop.AfterReturningAdvice (后置通知:在方法后)
  • org.aopalliance.intercept.MethodInterceptor (环绕通知:方法前后)
  • org.springframework.aop.ThrowsAdvice (异常抛出通知:方法抛出异常)
  • org.springframework.aop.IntroductionInterceptor (引介通知: 类中增加新的方法属性)
方式一:使用Spring的API接口

接口

public interface UserService {
    void add();

    void delete();

    void update();

    void select();
}

实现

public class UserServiceImpl implements UserService {
    public UserServiceImpl() {
    }

    public void add() {
        System.out.println("增加了一个用户");
    }

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

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

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

前置通知

import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;

public class Log implements MethodBeforeAdvice {
    // method 要执行的目标对象的方法
    // args 参数
    // target 目标对象
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println(target.getClass().getName()+"的"+method.getName()+"被执行了");
    }
}

后置通知

import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;

public class AfterLog implements AfterReturningAdvice {
    // returnValue 返回值
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("执行了"+method.getName()+"方法,返回结果为"+returnValue);
    }
}

配置文件applicationContext.xml




    
    
    

    
    
    
        
        
        
        
        
    


测试

public static void main(String[] args) {
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    // 动态代理 代理的是接口
    UserService userService = (UserService) context.getBean("userService");
    userService.add();
}
方式二:自定义类来实现AOP

自定义类

public class DiyPointCut {

    public void before666() {
        System.out.println("方法执行前");
    }

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

配置文件




    
    
        
        
        
        
        
    

方式三:使用注解方式实现AOP

注解类

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 AnnotationPointCut {

    @Before("execution(* com.spring.service.UserServiceImpl.*(..))")
    public void before() {
        System.out.println("方法执行前");
    }

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

    // 在环绕增强中,我们可以给定一个参数,代表我们要处理切入点
    @Around("execution(* com.spring.service.UserServiceImpl.*(..))")
    public void around(ProceedingJoinPoint jp) throws Throwable {
        System.out.println("环绕前");
        jp.proceed(); // 执行方法
        System.out.println("环绕后");
    }
}

配置文件






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

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

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