您的位置:首页 > 编程语言 > Java开发

Spring学习,依赖注入(DI)、控制反转(IoC)和面向切面(AOP)

2017-02-13 15:16 1016 查看
依赖注入DI和控制反转IoC
Spring容器中的依赖注入DI和控制反转IoC
xml配置

注解配置

面向切面AOP
面向切面的应用动态代理

Spring容器中的面向切面
xml配置

注解配置

Spring整合hibernate和AOP应用之声明式事务

依赖注入(DI)和控制反转(IoC)

在日常编码中经常遇到在一个类中调用另一个类的多个方法,所以就在一个类中new出需要用到的类,也就是组合模式。比如说A类里面需要用到很多B类里面的方法,所以要在A类里面new一个B。

public class A {

private B b = new B();

public void aa(){
b.bb();
}

}


但是这样有个弊端,就是类一开始就定死了,万一业务有变化需要别的实现呢?所以我们要面向接口编程。比如说A类里面需要B类,我们可以将B设计成接口,然后根据业务需求建立不同的B接口实现类B1,B2。。。这样需要什么样的实现就new什么实例。

package com.jyh.test;

public class A {

private B b = new B1();

public void aa(){
b.bb();
}

public interface B {
public void bb();
}

public class B1 implements B{

public void bb() {

}
}

public class B2 implements B{

public void bb() {

}
}

}


但是这样还不好,这样设计如果要改实现还要改A类里面的代码替换B接口的实现类,我们可以将实现丢给调用者来实现,在A类里面定义类型B的属性,外部调用者可以通过setter方法和构造方法给该属性赋值一个实现。

package com.jyh.test;

public class A {

private B b;

public A(B b) {
super();
this.b = b;
}

public B getB() {
return b;
}

public void setB(B b) {
this.b = b;
}

public void aa(){
b.bb();
}

public static interface B {
public void bb();
}

public static class B1 implements B{

public void bb() {
System.out.println("b1");
}
}

public static class B2 implements B{

public void bb() {
System.out.println("b2");
}
}

public static void main(String[] args) {
A a = new A(new B2());
a.aa();
}

}


这就是注入,将需要的实现通过某些方法给注入进去,依赖注入就是字面上的意思,因为A类的功能依赖B,所以注入B就称作依赖注入,意思就是依赖的东西的注入。而IoC(控制反转)的意思就是依赖的获取被反转了,本来A依赖B,所以A来创建一个实例,但是现在不是由A创建一个实例,而是别人创建好了实例传递给了A。

Spring容器中IoC部分就是做这种事,由Spring创建实例,由Spring进行注入。

Spring容器中的依赖注入(DI)和控制反转(IoC)

xml配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
ht
4000
tp://www.springframework.org/schema/beans/spring-beans.xsd">

<!--
lazy-init,懒加载,在获取bean的时候才创建实例
autowire:自动装配,<property ref/>是指定装配,autowire中byName值就是通过需要注入的属性名字匹配对应id查找bean
比如说本类中有个名为userDao的属性,那么就在这里查找id为userDao的bean来实例化
-->
<bean id="userService" class="com.jyh.service.impl.UserServiceImpl" lazy-init="true" autowire="byName">
<!-- property表示注入本类中的某个依赖,name为需要注入的依赖(属性)的名字,
ref指向另一个bean的id,也就是说对应属性的类型,如果是基本类型则就用value直接赋值
这个注入是setter方法注入 -->
<property name="userDao" ref="userDao" /><!-- bean -->
</bean>

<!-- dao -->
<bean id="userDao" class="com.jyh.dao.impl.UserDaoImpl"></bean>

<bean id="user" class="com.jyh.domain.User">
<!-- 基本类型用value直接赋值 -->
<property name="name" value="无名"></property>
</bean>

<!-- 构造方法注入 -->
<bean id="userServiceTwo" class="com.jyh.service.impl.UserServiceImpl">
<!-- 指向参数所带表示的实例bean,顺序按照构造方法参数的顺序 -->
<constructor-arg ref="userDao"></constructor-arg>
<!-- 按照参数类型赋值
<constructor-arg type="java.lang.String" value="构造注入"/> -->
<!-- 按照参数名赋值
<constructor-arg name="years" value="7500000"/>
<constructor-arg name="ultimateAnswer" value="42"/> -->
<!-- 按照参数顺序赋值
<constructor-arg index="0" value="7500000"/>
<constructor-arg index="1" value="42"/> -->
</bean>

</beans>


注解配置

编写注解前需要在xml配置文件中编写如下配置

<!-- 将该类下的所有类配置成bean,只需要在该包下的类前面加上@Component(value = beanid)注解就可以不用再配置文件中写bean -->
<context:component-scan base-package="com.jyh.annotation"></context:component-scan>

<!-- 启动注解 -->
<context:annotation-config></context:annotation-config>


注解

package com.jyh.annotation;

import javax.annotation.Resource;
/**
* 注解可以在属性上面也可以在setter方法上面,建议在setter上面
*/

import org.springframework.stereotype.Component;

@Component(value = "b") //有这个注解就代表着在配置文件中注册了bean(等同于bean标签),value值为bean的id,默认为首字母小写的类名
public class B {

private String name;

//这两个加一起等同于@Resource(name = "aaa")
//@Autowired                        //默认按照类型匹配
//@Qualifier(value = "aaa")         //名称匹配
private A a;
public String getName() {
return name;
}
//这个注解代表着这个属性是要通过spring注入来的,等同于bean标签下面的property标签
//name属性代表着该属性在配置文件中bean的id,也就是@Component()标签中的value,没写默认为属性名
@Resource(name = "a")
public void setName(String name) {
this.name = name;
}
public A getA() {
return a;
}
public void setA(A a) {
this.a = a;
}

}


面向切面(AOP)

砧板上放了一些面,一刀从中间切下,无论从面的这头到那头还是从那头回到这头都要经过刀面,刀面就是切面。

一个小区里面的人出小区要经过保安,要进小区也要经过保安,保安可以查看你是不是该小区的人,保安就是切面。

面向切面的应用:动态代理

JDK自带的动态代理(借助接口实现的动态代理)

//JDK自带的动态代理实现,利用接口
@Test
public void proxy(){
final UserDao userDao2 = new UserDaoImpl();
UserDao userDao = (UserDao)Proxy.newProxyInstance(UserDaoImpl.class.getClassLoader(),
userDao2.getClass().getInterfaces(),
new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(proxy.getClass().getName());
System.out.println("动态代理");
method.invoke(userDao2,args);
return null;
}
});
userDao.say("nnn");
}


cglib的动态代理(不需要接口的动态代理)

//cglib实现动态代理,不需要接口
@Test
public void cglibProxy(){
final UserDao userDao2 = new UserDaoImpl();
Enhancer enhancer = new Enhancer();
//设置拦截器
enhancer.setCallback(new MethodInterceptor() {

public Object intercept(Object arg0, Method arg1, Object[] arg2,
MethodProxy arg3) throws Throwable {
arg1.invoke(userDao2, arg2);
return null;
}
});
//设置传入被代理的类进去作为父类
enhancer.setSuperclass(userDao2.getClass());
//获取被代理类
UserDao userDao = (UserDao)enhancer.create();

userDao.say("cglib实现动态代理");
}


Spring容器中的面向切面

xml配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> 
<context:component-scan base-package="com.jyh.annotation"></context:component-scan>

<!-- 启动注解 -->
<context:annotation-config></context:annotation-config>
<!-- 注解aop -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

<!-- dao -->
<bean id="userDao" class="com.jyh.dao.impl.UserDaoImpl"></bean>

<!-- 切面类 -->
<bean id="myIntercept" class="com.jyh.aop.MyIntercept"></bean>

<!-- aop, proxy-target-class="true"设置用cglib实现代理 -->
<aop:config>
<!-- 切入点表达式 ,确定目标类,被代理的类,意思就是调用该类中的方法会触发切面 -->
<aop:pointcut expression="execution(* com.jyh.dao.impl.UserDaoImpl.*(..))"
id="myProxy" />
<!-- ref指向的对象就是切面,也就是公共调用的处理方法所在的类 -->
<aop:aspect ref="myIntercept">

<!-- 方法调用前的处理,method指向方法,pointcut-ref指向代理对象,也就是上面pointcut元素的id -->
<aop:before method="beforeMethod" pointcut-ref="myProxy" />

<!-- 方法调用后的处理 -->
<aop:after-returning method="afterMethod"
pointcut-ref="myProxy" returning="val" />

<!-- 无论有没有成功执行,最终都会调用这个方法 -->
<aop:after method="finallyMethod" pointcut-ref="myProxy" />

<!-- 异常通知 -->
<aop:after-throwing method="exceptionMethod"
throwing="ex" pointcut-ref="myProxy" />

<!-- 环绕通知,能控制目标方法执行不执行 -->
<aop:around method="aroundMethod" pointcut-ref="myProxy" />
</aop:aspect>
</aop:config>
</beans>


package com.jyh.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

public class MyIntercept {
public void beforeMethod(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
System.out.println("连接点的名称(方法名称):"+methodName);
System.out.println("目标类:"+joinPoint.getTarget().getClass());
System.out.println("方法调用前");
System.out.println("-------------------");
}

public void afterMethod(JoinPoint joinPoint,Object val){
System.out.println("目标方法的返回值:" + val);
System.out.println("方法调用后");
System.out.println("-------------------");
}

public void finallyMethod(){
System.out.println("最后始终会执行的方法");
System.out.println("-------------------");
}

public void exceptionMethod(JoinPoint joinPoint,Throwable ex){
System.out.println("异常执行的方法");
System.out.println(ex.getMessage());
System.out.println("-------------------");
}

public void aroundMethod(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("环绕控制前");
joinPoint.proceed();//调用目标方法
System.out.println("环绕控制后");
System.out.println("-------------------");
}
}


注解配置

<context:component-scan base-package="com.jyh.annotation"></context:component-scan>

<!-- 启动注解 -->
<context:annotation-config></context:annotation-config>
<!-- 注解aop -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>


package com.jyh.annotation;

import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

/**
* @Before方法执行前 @AfterReturning方法执行后 @After最终始终都会执行的方法
* @AfterThrowing异常执行的方法 @Around环绕
* @author OverrideRe
*
*/

@Component("D")
@Aspect                                                         //表示本类是切面
public class D {
//切入点,由于切入点都是方法,所以这里也定义一个方法作为切入点,没有实际意义
@Pointcut("execution(* com.jyh.annotation.C.*(..))")
private void cc(){};

@Before("cc()")
public void before(){
System.out.println("方法前");
}

@AfterReturning("cc()")
public void after(){
System.out.println("方法后");
}
}


Spring整合hibernate和AOP应用之声明式事务

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>

<session-factory>
<!-- 链接数据库的用户名 -->
<property name="connection.username">root</property>
<!-- 链接数据库的密码 -->
<property name="connection.password">ying1995520***</property>
<!-- 链接数据库的驱动 -->
<property name="connection.driver_class">
com.mysql.jdbc.Driver
</property>
<!-- 链接数据库的url -->
<property name="connection.url">
jdbc:mysql://localhost:3306/db3
</property>

<property name="dialect">org.hibernate.dialect.MySQLDialect</property>

<property name="hbm2ddl.auto">update</property>
<!-- 显示sql语句 -->
<property name="show_sql">true</property>
<!-- 格式化的显示sql语句 -->
<property name="format_sql">true</property>

<mapping resource="com/jyh/domain/Account.hbm.xml"/>

</session-factory>
</hibernate-configuration>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java spring java web aop