危险提示:这篇blog是写IOC和AOP时,会点出一些重点涉及到的java基础知识的,我感觉我身边太多人把基础丢了(我也算吧,学新知识时,也没想过联系基础,基础不算巩固,学东西都会很慢),推荐的链接也可以不用理,起码不影响这blog阅读。
Spring了解阶段总结,Spring的核心是控制反转(IOC)和面向切面(AOP),个人认为涉及的比较重要的基础是:创建对象的几种方式、接口声明与实现、面向对象三大特性、工厂原理、反射、泛型等。
1、传统JavaSE实例
这实例有接触接口、封装、工厂模式等重要基础知识,基础温习为了省点篇幅,基础温习就省略一下,但会推荐一些比较合适的基础温习博客。
我就写一个简单的传统javaSE的例子,是一个工厂模式中的工厂方法,后面作为对比用到。
第一步,写两个数据层的UserDao接口及其实现类,相当于工厂模式中生产的产品。
public interface UserDao {
public void getUser();
}
public class MysqlUserDaoImpl implements UserDao {
@Override
public void getUser() {
System.out.println("这里是测试获取Mysql数据库中的用户数据哦");
}
}
public class OracleUserDaoImpl implements UserDao {
@Override
public void getUser() {
System.out.println("这里是测试获取Oracle数据库中的用户数据哦");
}
}
第二步,写一个服务层的UserService的接口及其实现类,这相当于工厂了。注意:接口的思想就是“封装隔离”,这里隔离掉UserDao的实现类,不暴露给客户端,但可以暴露给工厂类。
public interface UserService {
public void getUser();
}
public class MysqlUserServiceImpl implements UserService {
//该处也是封装的一个例子,隐藏MysqlUserServiceImpl类的userDao信息
private UserDao userDao = new MysqlUserDaoImpl();
@Override
public void getUser() {
userDao.getUser();
}
}
public class OracleUserServiceImpl implements UserService {
//该处也是封装的一个例子,隐藏OracleUserServiceImpl类的userDao信息
private UserDao userDao = new OracleUserDaoImpl();
@Override
public void getUser() {
userDao.getUser();
}
}
第三步,写个测试类进行测试
@Test
public void test(){
UserService service = new MysqlUserServiceImpl ();
service.getUser();
}
推荐补blog:Java基础系列(九)接口、多态
推荐补blog:设计模式-创建型-工厂方法、四:设计模式实战:静态工厂方法、【设计模式】简单工厂、工厂方法与抽象工厂的区别、简单工厂(Java)
java封装上的就不推荐,反正找不到满意的,基本都在讲java属性的封装,比如猫狗人这类的封装,都是JavaBean。我的理解呢,直接一句话,只要是有隐藏信息,有对外提供简单接口的都是封装。
2、IOC的原型
但是,上面是不是很麻烦,代码量比较多,维护麻烦,假如有多一个DB2数据库,是不是又要从加多一个DB2的DAO实现类,DB2的Service实现类?那么怎么简单解决呢?
我是这样想的,Service的实现类都去掉,不管都扔了,只写下面这个实现类
//IOC原型的Server实现类
public class UserServiceImpl implements UserService {
private UserDao userDao;
//看到这,我想起了,这不是学匿名内部类的套路吗,后面肯定来一手玩玩
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void getUser() {
userDao.getUser();
}
}
仔细观察,不同的地方是,封装私有对象userDao,提供setUserDao给外界访问,让外界自己提供对应的userDao。
//旧的创建无参数的userDao
private UserDao userDao = new UserDaoImpl();
//新:封装私有对象userDao,提供setUserDao给外界访问,让外界自己提供对应的userDao
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
写一个测试类测试一下.
//@Test//旧的测试方法
//public void test(){
// UserService service = new UserServiceImpl();
// service.getUser();
//}
@Test
public void test(){
UserServiceImpl service = new UserServiceImpl();
service.setUserDao( new UserDaoMySqlImpl() );//IOC的原型,更多的去关注业务的实现
service.getUser();
service.setUserDao( new UserDao(){//直接用用匿名内部类来写,方便快捷,对应的Dao实现都不用写
@Override
public void getUser() {
System.out.println("这里是测试获取DB2数据库中的用户数据哦");
}
});
//在多加一个,用lambda表达式来写
service.setUserDao( () -> System.out.println("这里是测试获取Access数据库中的用户数据哦"););
}
本人对IOC的原型理解就大致到这先,反正就是由程序代码直接操控的对象的调用权交到外部解决就是了,这里涉及基础知识重要的有内部类和JAVA8新特性的lambda表达式。推荐补blog:简单说1.8前的接口和之后的接口不同,由已知的接口实现类或匿名函数类(已知知识)去了解lambda(未知知识)
3、IOC的实现原理
不过嘛,Spring 中的 IoC 的实现原理是工厂模式加反射机制;怎么能缺少反射呢?
拿网上的实例来说明,自己不编一个新的了。来源是:ThinkWon总结的Spring面试题
interface Fruit {
public abstract void eat();
}
class Apple implements Fruit {
public void eat(){
System.out.println("Apple");
}
}
class Orange implements Fruit {
public void eat(){
System.out.println("Orange");
}
}
class Factory {
public static Fruit getInstance(String ClassName) {
Fruit f=null;
try {
f=(Fruit)Class.forName(ClassName).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return f;
}
}
class Client {
public static void main(String[] a) {
Fruit f=Factory.getInstance("io.github.dunwu.spring.Apple");
if(f!=null){
f.eat();
}
}
}
反射的blog就不推荐了,搜一下就有一篇热门的可以拿来了解。
4、IOC概念
看完上面,大家都能很容易理解IOC概念了吧:
控制反转即IoC (Inversion of Control),它把传统JavaSE上由程序代码直接操控的对象的调用权交给容器,通过容器来实现对象组件的装配和管理。所谓的“控制反转”概念就是对组件对象控制权的转移,从程序代码本身转移到了外部容器。
Spring IOC 负责创建对象,管理对象(通过依赖注入(DI)),装配对象,配置对象,并且管理这些对象的整个生命周期。
最简单的例子我不给了,毕竟都有接触Spring了,我就各一段文字,看大家能不能想出对应的代码及步骤来。
创建一个实体类,只有一个成员变量叫message。然后在创建一个.xml文件,想通过bean注入名字:“欢迎关注我的博客,点赞呀”。之后创建一个测试类,里面新建一个IOC容器,IOC容器会帮忙创建对象,最后IOC容器通过getBean()方法,使"欢迎关注我的博客,点赞呀"注入到上述已创建的对象中。
我觉得还不能对Spring有一个初步了解,继续了解,拿一个很多人转发过的一段话来说明一下。
Spring所倡导的开发方式就是如此,所有的类都会在spring容器中登记,告诉spring你是个什么东西,你需要什么东西,然后spring会在系统运行到适当的时候,把你要的东西主动给你,同时也把你交给其他需要你的东西。所有的类的创建、销毁都由 spring来控制,也就是说控制对象生存周期的不再是引用它的对象,而是spring。对于某个具体的对象而言,以前是它控制其他对象,现在是所有对象都被spring控制,所以这叫控制反转。
Spring的最简单配置说明:id,创建的bean的名称;class,反射出类Hello的实例。其余配置省略。
<!--bean就是java对象 , 由Spring创建和管理
相当于
类型 变量名 = new 类型();
即:Hello hello = new Hello();
其中 id = 变量
class = new 的对象
property 相当于给对象中的属性设置一个值!
-->
<bean id="helloword" class="com.xxxx.xxxx.HelloWord">
<property name="name" value="Spring"/>
</bean>
5、Spring其余知识点
例如,依赖注入、自动装配、注解开发、声明事务等省略,需要了解的,推荐看视频或者书,这blog只是本人对IOC和AOP的理解,以及对所学知识的总结、知识点的联系和个人见解。如果新人对Spring等java知识没了解的,推荐这blog,很通俗,非常适合新人入手:狂神说
5、AOP
5.1 前置知识:
前置知识:OOP。OOP(Object-Oriented Programming)面向对象编程,允许开发者定义纵向的关系,但并适用于定义横向的关系,导致了大量代码的重复,而不利于各个模块的重用。
前置知识:静态代理和动态代理。跳转连接静态/动态代理模式。
不过也简单说一下两者区别:静态代理会为每一个业务增强都提供一个代理类, 由代理类来创建代理对象, 而动态代理并不存在代理类, 代理对象直接由代理生成工具动态生成.
5.2 AOP概念
AOP(Aspect-Oriented Programming),一般称为面向切面编程,作为面向对象的一种补充,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被命名为“切面”(Aspect),减少系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。可用于权限认证、日志、事务处理等。
5.3 AOP简单实例
例如,在我们开发过程中,写好增删改查了,突然要加人一个针对增删改查的日志。那么第一步,写个log类,这就是切面的面。第二步,就是确定切面的工作,也就是log类的方法,例如在执行增删改查时,日志上就写入对应的增删改查信息。第三步,确定目标,即确定是目标的增删改查。第四步,写个xml文件,直接把目标的增删改查的实现类注册到spring中。第五步,切入点,在上述xml文件中配置aop,写明要在目标增删改查方法中切入日志类要执行的方法,就是第二步说的方法。第六步,在测试类或者控制层执行增删改查时,写个动态代理的增删改查接口作为日志的接入点,然后接口去执行增删改查时,就自动执行日志,不影响增删改查运行。
好吧,上面说啥,直接给连接跳转看代码实例吧!真的太通俗易懂了,我就节省篇幅了,blog上能找到的替代品拿出来用就行了。