AOP:面向切面

面向对象和面向切面,即从面对一个个的实体对象,变为面向一个个的过程。

以多种用户对象登录为例:
面向对象就是定义多种用户的对象,包括普通用户、会员、超级会员等,每种用户都有登录的功能,且登录的功能代码相同。

如果不使用AOP,那就是每种用户,都需要为其写一个登录的功能,重复多次。

如果使用AOP,就只用写一个登录的功能,然后使每种用户都使用这个登录的功能,而每个用户对象本身不需要登录的功能。

AOP一般使用在日志、权限控制等。

使用AOP的好处:

  1. 解耦合,可以在业务逻辑不变的情况下对业务代码的功能进行增强。
  2. 简洁,不必写重复的代码,对同样的功能拦截进行统一处理。

也就是说,如果我们需要对用户的登录过程进行修改,我们不需要修改所有的需要登录的对象,而只需要修改这一个登录“功能”就可以了。

控制反转(IOC)

控制反转的概念和依赖注入是分不开的。

控制反转的意思就是,从原先的对象由java代码控制,变为了由spring容器来统一管理(具体的控制方式就是applicationContext等配置文件或注释)。这就是所谓的控制反转,被容器管理的对象被成为 bean 。

创建bean共有三种方式:

  1. xml配置bean
  2. 注解配置bean(@Service,@Controller,@Component)
  3. java类产生bean(@Configuration配置文件,@Bean产生bean)

第三种示例:

@Configuration
public class DataSourceConfig {
	@ConfigurationProperties(prefix = "spring.datasource")
    @Bean
    public DataSource dataSource(){
       return new DataSource();
    }
}

那Spring容器通过怎么配置管理类做这些bean呢?

Spring自动化配置的方式:

  1. 组件扫描,扫描这些:@Service,@Controller,@Component
  2. 自动装配,将bean中使用到的其他bean注入进来(见下文)

那为什么要这样呢?
由Spring容器来管理对象,更加的高效、灵活。
举个例子:
我们的开发环境有测试、线上两个环境。
两个环境连接的数据库不同。如果将数据库的连接信息放在java代码中,那我们需要根据不同的数据库,写两个不同版本的代码。
如果由Spring容器管理,只需要在不同的环境下使用不同的配置文件即可。

再比如说,如果我们的数据库信息更改了,我们只需要修改数据库信息的配置文件,而不需要再修改java代码等。

依赖注入(DI)

控制反转是离不开依赖注入的。实现控制反转,也就是实现容器控制对象,依赖注入便提供了注入对象的功能。

依赖注入就是根据注解,或者配置文件,将实例bean,赋给到java程序,而不是让java程序自己通过new来创建。

当然,有的bean中需要用到其他bean,这就涉及到对象之间的相互关联。将bean之间关联起来,就是装配的过程。

注入和装配的区别:
注入偏向于“赋值”的过程,它将真正的对象“给到”程序;装配偏向于查找的关系的过程,它将找到各个bean之间的“组合关系”。

Spring的三种注入方式:

  • 构造器注入
  • setter方法注入
  • 注解注入(@Resource等),原理是反射直接注入

Spring的几种装配方式:

  • 没有(no,默认),就是不自动装配,必须通过 ref 元素定义Bean 依赖。
  • 按类型(byType),查找相应类型的bean,进行注入,@Autowired
  • 按名称(byName),查找相应名称的bean,进行注入,@Resource
  • 构造器(constructor),查找相应类型的bean,通过构造器进行注入,可以在构造器中进行一些操作
  • autodetect,相当于byType 和 constructor,如果发现默认的构造方法,则用 constructor 模式,否则用 byType 模式。

以user类(用户)和goods类(商品)为例:
一般来说,当一个user对象想调用一个goods对象时,需要new一个goods对象,这样就会将这两个对象紧紧地联系在一起,耦合性很高,不利于后续的修改、维护。

而spring采用了依赖注入的方式,统一通过spring容器来创建对象,而不是通过new来调用一个对象。
而对象之间的关系,也是通过spring容器来定义,而不是让对象自己来控制。
如:当一个user对象想调用一个goods对象时,只需要从applicationContext中找到自己依赖的goods对象,然后使用它。

依赖注入的具体体现就是applicationContext以及注解。

反射

Java的反射机制就是:给一个未知的对象,找到它是什么类,它的方法,属性(变量)等等。
如,现在有很多个类,但是我不知道最终会使用哪个类。
那就只好定义一个Object obj。
当我确定使用某个类(如user)时,obj本身又不知道user的方法、属性等。
这时,就需要用到反射,通过如下操作使obj可以使用user的方法、属性。

Class cla = Class.forName("user");//找到user类
Constructor userConstructor = cla.getConstructor(); //找到user的构造器
obj = userConstructor.newInstance();//实例化一个user对象
Method setIdMethod = cla.getMethod("setId", int.class);//找到需要使用的方法
setIdMethod.invoke(obj, 14);//使用相应的方法

反射在我们平时使用时,似乎是很少用到,但其实是无处不在。
比如:我们知道spring容器通过applicationContext中的来实现对象的实例化。但具体是怎么实现的呢?其实就是通过反射机制。
如下:

它的实例化过程如下:

String idStr="user";
String classStr="com.dao.user";
Class<?> cls = Class.forName(classStr);
Object obj = cls.newInstance();
container.put(idStr, obj);//加入到Spring容器中