Spring-IOC

IOC(控制翻转)的核心理念是将对象交由Spring容器来进行管理,Spring来管理对象的生成和装配,用户只用关心业务层的具体实现,而不用去管理对象的生命周期。

注册对象到容器中的方法有很多、最早都是在xml文件中配置的,后来为了简化开发,就出现了注解方式,二者本质是一样的。s

使用注解将对象加入到Spring容器中

使用注解的前提条件是开启注解支持和配置扫描包,下面提供两种方式:

  • xml方式的配置:
    配置注解支持: <context:annotation-config/>
    配置扫描包: <context:component-scan base-package=“com.java.**”/>
  • 注解方式配置
    配置扫描包:@ComponentScan()
    开启注解支持:@EnableAutoConfiguration
注册bean到Spring容器中

@compoent: 用在类上,将该类加入到Spring容器中,这跟在xml文件中配置bean是一样的,spring容器中的bean的名称就是类名的小写。

@compoent的衍生注解:

1.dao层:@repository

2.service层:@service

3.controller层:@controller

这三个注解在本质上是没有区别的,都是将类加入到spring容器中,只是按照MVC三层架构来进行了区分。

依赖注入: Spring中IOC的具体实现就是依赖注入,依赖注入有三种方式
  • 通过构造器的方式注入
@Service
public class UserServiceImpl{
	private UserMapper userMapper;
	//通过构造器的方式注入
	public UserServiceImpl(UserMapper userMapper){
		this.userMapper = userMapper;
	}
}
  • 通过set方法注入
@Service
public class UserServiceImpl{
	private UserMapper userMapper;
	//通过set方法注入
	public void setUserMapper(userMapper userMapper){
    this.user
  }
}
  • 使用注解注入
  1. @autowired: 按照类型(类)来进行注入,如果用的时候在Spring中的上下文中找不到,会报空指针异常
  2. @resource: 先按照名称来进行注入,如果找不到,再按照类型进行注入,如果两个都找不到会报错(功能强大,性能略微不如autowired)

@Qualifier(value=“xxx”),结合antowired使用,使用这个可以按照这个xxx名称去容器中寻找对应的bean

@Scope配置作用域:@Scope(“singleton”):单例模式容器中只有一个实例,spring容器中默认使用单例模式

@Scope(“prototype”):原型模式,每一个注入都会生成一个单独的bean

赋值操作
  • @Nullable添加这个注解,说明这个字段可以为空
  • @Value(“xxx”)给字段加上值
    4. 配置
  • @ComponentScan:设置扫描包,去寻找需要注册到容器中的组件,通常在spingboot启动类中使用
  • @Configuration:在类上加上这个注解,就相当于xml中的,代表着一个配置类
    然后需要写一个方法,在方法里面返回需要注册的bean,加上@bean注解
  • 配置类写法
@Configuration
@CompoentScan("com.java.openresource")
public class testConfig{
  @Bean
  public User getUser(){
    return new User();
  }
}
注意:bean中注册的名字就是方法名,User中需要使用@Component注解,将该类加入到容器中
  getUser等价于xml中id、返回值等价于class
  • xml写法
<beans>
	<bean id="user" class="com.java.opensource.entity.user">
	</bean>
</beans>

以上两种写法是等价的!


Spring-AOP

Spring实现的核心是动态代理,学会代理思想可以加深对Spring AOP的理解

代理模式:

租房人、中介、房东(接口 真实角色 代理角色 客户端)

概述:现在有一个人想租房、还有一个房东想出租,这时候用户找不到房源,房东找不到客户,双方都达不到目的,于是中介就来了,中介承上启下,中介负责带我们看房,来办理合同相关事情, 房东只需按月收钱就行,不用关心跟客户对接的一大推事情,用户和房东的问题就得到了解决,这个中介其实就扮演了一个代理的角色。

代理模式优点:

1.可以使真实角色的操作更加纯粹,不用去关注公共的业务(房东只想租房出去,不想去看房什么的)

2.公共部分交给代理来使用(代理可以实现看房、联系管家等)

3.公共业务发生扩展的时候,方便集中管理

缺点:一个真实角色就会产生一个代理角色,代码量会翻倍。

1.静态代理:

静态代理就是重新实现一个接口,也就是创建一个代理类,然后去调用原来的实现类,在方法的前后加上特定内容,可以实现在不改变原有代码的基础上对方法进行增强。

缺点:不容易维护,当一个接口有多个实现类的时候,就要基于不同的实现类来进行编写特定的代理类、

2.动态代理:

一个动态代理类可以代理多个类,通常指的是一类业务,不用手动去实现代理类,操作简单,更容易维护,功能强大。

动态代理实现的代码实例:

需求:有一个用户接口,有增删改查四个操作,现在想通过动态代理的方法在执行每个方法前加上对应日志

//接口
public interface UserService {

    void add();

    void remove();

    void update();

    void query();
}
//实现类
public class UserServiceImpl implements UserService {
    @Override
    public void add() {
        System.out.println("实现了添加方法");
    }

    @Override
    public void remove() {
        System.out.println("实现了删除方法");
    }

    @Override
    public void update() {
        System.out.println("实现了修改方法");
    }

    @Override
    public void query() {
        System.out.println("实现了查询方法");
    }
}
//代理调用处理器
public class ProxyInvokeHandler 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 Throwable {
        addOperateLog(method.getName());
        return method.invoke(target, args);
    }

    private void addOperateLog(String operateStr) {
        System.out.println("新增日志:执行了" + operateStr + "方法");
    }
}

//执行测试
public class TestProxy {
    public static void main(String[] args) {
        UserServiceImpl userService = new UserServiceImpl();
        ProxyInvokeHandler proxyInvokeHandler = new ProxyInvokeHandler();
        proxyInvokeHandler.setTarget(userService);
        UserService proxy = (UserService) proxyInvokeHandler.getProxy();
        proxy.remove();
    }
}
  • aop底层包括很多框架的底层都是通过反射实现的
  • 动态代理代理的是接口
  • 动态代理有两种实现方式
  • jdk自带的
  • cglib实现的

这个可以去配置

动态代理是AOP的底层实现,实际使用中可以直接使用注解来进行开发

@Aspect:标记这个类为切面

  • @Before:在方法执行之前执行
  • @After:在方法执行之后执行
    实例:@After(“execution(* com.java.opensource.UserServiceImpl.*(…)”);
@Aspect
public class logConfig{
  
  @After("execution(* com.java.opensource.UserServiceImpl.*(..)")
  public void addLog(){
    System.out.print("在方法的执行之后添加一条日志信息");
  }
}

作用:执行UserServiceImpl中的任意方法时,会在方法执行完毕的时候增加一条这样的日志信息。

*(…)代表任何参数:具体参考execution表达式

以上就是本篇文章的全部内容了,如果想更深层次的了解Spring相关知识,我推荐这篇Spring中文文档、如果有问题,欢迎大家留言交流!