本文共 19507 字,大约阅读时间需要 65 分钟。
Spring学习笔记(
9
)----让Spring自动扫描和管理Bean
-------------------------------------------------
Java代码
1
.
package
com.szy.spring.service;
2
.
3
.
import
org.springframework.stereotype.Service;
4
.
5
.
import
com.szy.spring.dao.PersonDao;
6
.
@Service
(
"service"
)
7
.
public
class
UserServiceImpl
implements
UserService
8
.{
9
.
private
PersonDao personDaoBean;
10
.
11
.
public
void
show()
12
. {
13
. personDaoBean.show();
14
. }
15
.
16
.
public
void
setPersonDaoBean(PersonDao personDaoBean)
17
. {
18
.
this
.personDaoBean = personDaoBean;
19
. }
20
.}
在前面的例子中,都是使用XML的bean定义来使用组件,在大的项目中,通常会有上百个组件,如果这些组件采用xml的bean定义来配置,显然会使配置文件显得很臃肿,查找和维护起来不方便。Spring2.
5
为我们引入了组件自动扫描机制,它可以在类路径下寻找标记了
@Component
、
@Service
、
@Controller
、
@Repository
注解的类,并把这些类纳入到spring容器中管理,它的作用和在xml中使用bean节点配置组件一样。要使用自动扫描机制,我们需要把配置文件如下配置:
Xml代码
1
.<?xml version=
"1.0"
encoding=
"UTF-8"
?>
2
.<beans xmlns=
"http://www.springframework.org/schema/beans"
3
. xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
4
. xmlns:context=
"http://www.springframework.org/schema/context"
5
. xmlns:tx=
"http://www.springframework.org/schema/tx"
6
. xsi:schemaLocation="http:
//www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
7
. http:
//www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
8
. http:
//www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
9
. <context:component-scan base-
package
=
"com.szy.spring"
></context:component-scan>
10
.</beans>
其中base-
package
为需要扫描的包(包括子包)
@Service
用于标注业务层的组件,
@Controller
用于标注控制层组件(如struts中的action),
@Repository
用于标注数据访问组件,即DAO组件,而
@Component
泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。但是在目前的spring版本中,这几个注解的作用是一样的,但是在以后可能会进行区分。
下面把先前的例子修改一下:
首先是PersonDaoBean类,修改如下
Java代码
1
.
package
com.szy.spring.dao;
2
.
3
.
import
org.springframework.stereotype.Repository;
4
.
5
.
@Repository
6
.
//告诉spring这个类要交给spring管理,
7
.
public
class
PersonDaoBean
implements
PersonDao
8
.{
9
.
public
void
show()
10
. {
11
. System.out.println(
"执行PersonDaoBean中的add()方法"
);
12
. }
13
.}
然后是UserServiceImpl类
Java代码
1
.
package
com.szy.spring.service;
2
.
3
.
import
org.springframework.stereotype.Service;
4
.
5
.
import
com.szy.spring.dao.PersonDao;
6
.
@Service
7
.
//把这个类交给spring管理,作为服务了。
8
.
public
class
UserServiceImpl
implements
UserService
9
.{
10
.
private
PersonDao personDaoBean;
11
.
12
.
public
void
show()
13
. {
14
. personDaoBean.show();
15
. }
16
.
17
.
public
void
setPersonDaoBean(PersonDao personDaoBean)
18
. {
19
.
this
.personDaoBean = personDaoBean;
20
. }
21
.
22
.
public
PersonDao getPersonDaoBean()
23
. {
24
.
return
personDaoBean;
25
. }
26
.}
下面我们进行测试,原来的测试代码是userServiceImpl
Java代码
1
.ApplicationContext ctx=
new
ClassPathXmlApplicationContext(
"applicationContext.xml"
);
2
. UserService service=(UserService)ctx.getBean(
"userService"
);
3
. service.show();
其中userService是我们在配置文件中配置的bean的id。但是如今我们并没有id这个属性,在spring2.
5
中,默认的id是类的名称,但是开后是小写,也就是userServiceImpl,因此测试代码应修改如下:
Java代码
1
.AbstractApplicationContext ctx=
new
ClassPathXmlApplicationContext(
"applicationContext.xml"
);
2
. UserService service=(UserService)ctx.getBean(
"userServiceImpl"
);
3
. System.out.println(service);
如果我们想自己命名的话,则只需在注解后加上括号,里面写入你希望的名字,如
@Service
(
"userService"
)。
在spring中默认的是之生成一个bean实例,如果我们想每次调用都产生一个实例,则标注需如下配置
@Service
@Scope
(
"prototype"
)
在xml中我们还可以配置初始化方法和销毁方法,使用标注后只需如下标注
Java代码
1
.
@PostConstruct
2
.
public
void
init()
3
. {
4
. System.out.println(
"初始化"
);
5
. }
6
.
@PreDestroy
7
.
public
void
destory()
8
. {
9
. System.out.println(
"销毁"
);
10
. }
使用注解后,我们的xml文件变得十分简单,因此建议Spring学习笔记(
10
)----公共属性的注入配置大家在以后的开发中使用注解。
Spring学习笔记(
10
)----公共属性的注入配置
-------------------------------------------
假设我们定义了四个bean类,其代码分别如下:
Java代码
1
.
package
com.szy.spring.bean;
2
.
3
.
public
class
Bean1 {
4
.
private
Bean2 bean2;
5
.
private
Bean3 bean3;
6
.
private
Bean4 bean4;
7
.
8
.
public
Bean2 getBean2()
9
. {
10
.
return
bean2;
11
. }
12
.
public
void
setBean2(Bean2 bean2)
13
. {
14
.
this
.bean2 = bean2;
15
. }
16
.
public
Bean3 getBean3()
17
. {
18
.
return
bean3;
19
. }
20
.
public
void
setBean3(Bean3 bean3)
21
. {
22
.
this
.bean3 = bean3;
23
. }
24
.
public
Bean4 getBean4()
25
. {
26
.
return
bean4;
27
. }
28
.
public
void
setBean4(Bean4 bean4)
29
. {
30
.
this
.bean4 = bean4;
31
. }
32
.}
Java代码
1
.
package
com.szy.spring.bean;
2
.
3
.
public
class
Bean2
4
.{
5
.
private
int
id;
6
.
private
String name;
7
.
private
String password;
8
.
9
.
public
int
getId()
10
. {
11
.
return
id;
12
. }
13
.
public
void
setId(
int
id)
14
. {
15
.
this
.id = id;
16
. }
17
.
public
String getName()
18
. {
19
.
return
name;
20
. }
21
.
public
void
setName(String name)
22
. {
23
.
this
.name = name;
24
. }
25
.
public
String getPassword()
26
. {
27
.
return
password;
28
. }
29
.
public
void
setPassword(String password)
30
. {
31
.
this
.password = password;
32
. }
33
.}
Java代码
1
.
package
com.szy.spring.bean;
2
.
3
.
public
class
Bean3
4
.{
5
.
private
int
id;
6
.
private
String name;
7
.
8
.
public
int
getId()
9
. {
10
.
return
id;
11
. }
12
.
public
void
setId(
int
id)
13
. {
14
.
this
.id = id;
15
. }
16
.
public
String getName()
17
. {
18
.
return
name;
19
. }
20
.
public
void
setName(String name)
21
. {
22
.
this
.name = name;
23
. }
24
.}
Java代码
1
.
package
com.szy.spring.bean;
2
.
3
.
public
class
Bean4
4
.{
5
.
private
int
age;
6
.
7
.
public
int
getAge()
8
. {
9
.
return
age;
10
. }
11
.
public
void
setAge(
int
age)
12
. {
13
.
this
.age = age;
14
. }
15
.}
按照正常的思路,我们下面就要给每个类进行属性的注入,配置文件如下设置:
Xml代码
1
.<?xml version=
"1.0"
encoding=
"UTF-8"
?>
2
.<beans xmlns=
"http://www.springframework.org/schema/beans"
3
. xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
4
. xmlns:context=
"http://www.springframework.org/schema/context"
5
. xmlns:tx=
"http://www.springframework.org/schema/tx"
6
. xsi:schemaLocation="http:
//www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
7
. http:
//www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
8
. http:
//www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
9
. <bean id=
"bean1"
class
=
"com.szy.spring.bean.Bean1"
>
10
. <property name=
"bean2"
ref=
"bean2"
/>
11
. <property name=
"bean3"
>
12
. <ref bean=
"bean3"
/>
13
. </property>
14
. <property name=
"bean4"
ref=
"bean4"
/>
15
. </bean>
16
.
17
. <bean id=
"bean2"
class
=
"com.szy.spring.bean.Bean2"
>
18
. <property name=
"id"
value=
"100"
/>
19
. <property name=
"name"
>
20
. <value>kuka</value>
21
. </property>
22
. <property name=
"password"
value=
"123"
/>
23
. </bean>
24
.
25
. <bean id=
"bean3"
class
=
"com.szy.spring.bean.Bean3"
>
26
. <property name=
"id"
value=
"100"
/>
27
. <property name=
"name"
value=
"kuka"
/>
28
. </bean>
29
.
30
. <bean id=
"bean4"
class
=
"com.szy.spring.bean.Bean4"
>
31
. <property name=
"age"
value=
"22"
/>
32
. </bean>
33
.</beans>
我们进行测试:
Java代码
1
.
@Test
2
.
public
void
testMethod()
throws
Exception
3
. {
4
. ApplicationContext ctx=
new
ClassPathXmlApplicationContext(
"applicationContext.xml"
);
5
. Bean1 bean1 = (Bean1)ctx.getBean(
"bean1"
);
6
.
7
. System.out.println(
"bean1.bean2.id="
+ bean1.getBean2().getId());
8
. System.out.println(
"bean1.bean2.name="
+ bean1.getBean2().getName());
9
. System.out.println(
"bean1.bean2.password="
+ bean1.getBean2().getPassword());
10
. System.out.println(
"bean1.bean3.id="
+ bean1.getBean3().getId());
11
. System.out.println(
"bean1.bean3.name="
+ bean1.getBean3().getName());
12
. System.out.println(
"bean1.bean4.age="
+ bean1.getBean4().getAge());
13
. }
正常输出我们所预期的信息,但是我们观察发现bean2和bean3的部分属性的配置信息是相同的,这仅是两个bean,如果是多个bean的话我们要修改就好修改多处,因此我们可以把这些公共的部分提出出来,进行抽象。这个在Spring中是支持的。我们在建立一个配置文件,命名为:applicationCommon.xml,其内容如下配置
Xml代码
1
.<?xml version=
"1.0"
encoding=
"UTF-8"
?>
2
.<beans xmlns=
"http://www.springframework.org/schema/beans"
3
. xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
4
. xmlns:context=
"http://www.springframework.org/schema/context"
5
. xmlns:tx=
"http://www.springframework.org/schema/tx"
6
. xsi:schemaLocation="http:
//www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
7
. http:
//www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
8
. http:
//www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
9
. <bean id=
"beanAbstract"
abstract
=
"true"
>
10
. <property name=
"id"
value=
"100"
/>
11
. <property name=
"name"
value=
"kuka"
/>
12
. </bean>
13
.
14
. <bean id=
"bean2"
class
=
"com.szy.spring.bean.Bean2"
parent=
"beanAbstract"
>
15
. <property name=
"password"
value=
"123"
/>
16
. </bean>
17
.
18
. <bean id=
"bean3"
class
=
"com.szy.spring.bean.Bean3"
parent=
"beanAbstract"
/>
19
.
20
.</beans>
beanAbstract就是我们抽象出来的,设置
abstract
=
"true"
属性后就不需要指定
class
属性。
我们把原来配置文件里的关于bean2和bean3节点注释掉。
下面进行测试,在这里要注意由于我们使用了两个配置文件,因此我们在读取是要写两个配置文件名。我们查看ClassPathXmlApplicationContext源文件发现其有个构造函数参数是string数组,因此我们可以把这个配置文件名放在数组里面。此外我们还有另外一种实现方法,两个配置文件一个叫applicationContext.xml,另一个applicationCommon.xml,公共部分是applicationC*.xml,下面我们就可以这样进行测试:
Java代码
1
.
@Test
2
.
public
void
testMethod()
throws
Exception
3
. {
4
. ApplicationContext ctx=
new
ClassPathXmlApplicationContext(
"applicationC*.xml"
);
5
. Bean1 bean1 = (Bean1)ctx.getBean(
"bean1"
);
6
.
7
. System.out.println(
"bean1.bean2.id="
+ bean1.getBean2().getId());
8
. System.out.println(
"bean1.bean2.name="
+ bean1.getBean2().getName());
9
. System.out.println(
"bean1.bean2.password="
+ bean1.getBean2().getPassword());
10
. System.out.println(
"bean1.bean3.id="
+ bean1.getBean3().getId());
11
. System.out.println(
"bean1.bean3.name="
+ bean1.getBean3().getName());
12
. System.out.println(
"bean1.bean4.age="
+ bean1.getBean4().getAge());
13
. }
如果我们bean2的name属性的值不是kuka,那么我们只需在applicationCommon.xml文件的bean2节点下再添加property属性即可
Xml代码
1
.<property name=
"name"
value=
"coolszy"
/>
Spring学习笔记(
11
)----自定义属性编辑器
-------------------------------------------
前面我们所定义的属性都是几本的属性,如果我们定义一个属性是Date类型,例如如下类中:
Java代码
1
.
package
com.szy.spring.bean;
2
.
3
.
import
java.util.Date;
4
.
5
.
public
class
Bean {
6
.
private
Date date;
7
.
8
.
public
Date getDate()
9
. {
10
.
return
date;
11
. }
12
.
public
void
setDate(Date date)
13
. {
14
.
this
.date = date;
15
. }
16
.}
按照我们以前学过的知识我们需要在配置文件中给该属性注入值
Xml代码
1
.<bean id=
"bean"
class
=
"com.szy.spring.bean.Bean"
>
2
. <property name=
"date"
value=
"2009-11-21"
/>
3
. </bean>
下面我们测试是否成功注入值
Java代码
1
.ApplicationContext ctx=
new
ClassPathXmlApplicationContext(
"applicationContext.xml"
);
2
. Bean bean = (Bean)ctx.getBean(
"bean"
);
3
. System.out.println(bean.getDate());
运行包如下异常
Exception代码
1
.org.springframework.beans.factory.BeanCreationException: Error creating bean with name
'bean'
defined in
class
path resource [applicationContext.xml]: Initialization of bean failed; nested exception is org.springframework.beans.TypeMismatchException: Failed to convert property value of type [java.lang.String] to required type [java.util.Date]
for
property
'date'
; nested exception is java.lang.IllegalArgumentException: Cannot convert value of type [java.lang.String] to required type [java.util.Date]
for
property
'date'
: no matching editors or conversion strategy found
通过错误提示信息我们得知spring不能将string转换成date类型,没有匹配的编辑器或者转换机制。
如果想实现string转换成Date,那么我们自己需要写一个属性编辑器
我们新建一个类DatePropertyEditor,这个类要继承PropertyEditorSupport类。
我们需要复写这个类中的setAsText方法,其中text参数就是配置文件中的值。我们的任务就是把text转换成date类型的值。
Java代码
1
.
package
com.szy.spring.util;
2
.
3
.
import
java.beans.PropertyEditorSupport;
4
.
import
java.text.SimpleDateFormat;
5
.
import
java.util.Date;
6
.
7
.
public
class
DatePropertyEditor
extends
PropertyEditorSupport
8
.{
9
.
10
.
@Override
11
.
public
void
setAsText(String text)
throws
IllegalArgumentException
12
. {
13
. String format=
"yyyy-MM-dd"
;
14
. SimpleDateFormat sdf=
new
SimpleDateFormat(format);
15
.
try
16
. {
17
. Date date=sdf.parse(text);
18
.
this
.setValue(date);
//把转换后的值传过去
19
. }
catch
(Exception e)
20
. {
21
. e.printStackTrace();
22
. }
23
. }
24
.
25
.}
写完编辑器后我们还需要把编辑器注入到spring中。 为了方便管理我们再新建一个配置文件applicationEditor.xml,用来配置属性编辑器
Xml代码
1
.<?xml version=
"1.0"
encoding=
"UTF-8"
?>
2
.<beans xmlns=
"http://www.springframework.org/schema/beans"
3
. xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
4
. xmlns:context=
"http://www.springframework.org/schema/context"
5
. xmlns:tx=
"http://www.springframework.org/schema/tx"
6
. xsi:schemaLocation="http:
//www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
7
. http:
//www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
8
. http:
//www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
9
. <bean id=
"customEditorConfigurer"
class
=
"org.springframework.beans.factory.config.CustomEditorConfigurer"
>
10
. <!-- 把值注入到CustomEditorConfigurer的 Map类型的customEditors属性-->
11
. <property name=
"customEditors"
>
12
. <map>
13
. <entry key=
"java.util.Date"
>
14
. <!-- 内部bean只供自己使用 -->
15
. <bean
class
=
"com.szy.spring.util.DatePropertyEditor"
/>
16
. </entry>
17
. </map>
18
. </property>
19
. </bean>
20
.
21
.</beans>
下面我们修改下测试代码已读取所有的配置文件
Java代码
1
.ApplicationContext ctx=
new
ClassPathXmlApplicationContext(
"application*.xml"
);
2
. Bean bean = (Bean)ctx.getBean(
"bean"
);
3
. System.out.println(bean.getDate());
最后测试,成功输出时间。
刚才我们在配置文件中时间的格式是
2009
-
11
-
21
,如果我们修改成
2009
/
11
/
21
呢?
运行报错:Unparseable date:
"2009/11/21"
这时我们需要修改属性编辑器类文件的格式了,很麻烦。既然spring支持注入,那么我们为什么不对格式进行注入呢?
修改属性编辑器类:
Java代码
1
.
package
com.szy.spring.util;
2
.
3
.
import
java.beans.PropertyEditorSupport;
4
.
import
java.text.SimpleDateFormat;
5
.
import
java.util.Date;
6
.
7
.
public
class
DatePropertyEditor
extends
PropertyEditorSupport
8
.{
9
.
10
.
private
String format;
11
.
@Override
12
.
public
void
setAsText(String text)
throws
IllegalArgumentException
13
. {
14
.
15
. SimpleDateFormat sdf=
new
SimpleDateFormat(format);
16
.
try
17
. {
18
. Date date=sdf.parse(text);
19
.
this
.setValue(date);
//把转换后的值传过去
20
. }
catch
(Exception e)
21
. {
22
. e.printStackTrace();
23
. }
24
. }
25
.
public
String getFormat()
26
. {
27
.
return
format;
28
. }
29
.
public
void
setFormat(String format)
30
. {
31
.
this
.format = format;
32
. }
33
.}
同时给该类对应的bean添加属性节点
Xml代码
1
.<bean
class
=
"com.szy.spring.util.DatePropertyEditor"
>
2
. <property name=
"format"
value=
"yyyy/MM/dd"
></property>
3
. </bean>
下次只要我们修改配置文件即可,灵活性很大。
Spring学习笔记(
12
)----静态代理模式分析演示
--------------------------------------------
代理模式分为静态代理和动态代理。静态代理就是我们自己定义的代理类,动态代理是程序在运行时生成的代理类。
下面演示下静态代理类。首先我们要定义一个接口:
Java代码
1
.
package
com.szy.spring;
2
.
3
.
public
interface
UserManager
4
.{
5
.
public
void
addUser(String username,String password);
6
.
public
void
deleteUser(
int
userId);
7
.
public
void
modifyUser(
int
userId,String username,String password);
8
.
public
void
findUser(
int
userId);
9
.}
比较常见的对用户进行增删改查。
下面我们常见一个实现类,实现这个接口。
Java代码
1
.
package
com.szy.spring;
2
.
3
.
public
class
UserManagerImpl
implements
UserManager
4
.{
5
.
6
.
public
void
addUser(String username, String password)
7
. {
8
. System.out.println(
"--------UserManagerImpl.addUser()----------"
);
9
. }
10
.
11
.
public
void
deleteUser(
int
userId)
12
. {
13
. System.out.println(
"--------UserManagerImpl.deleteUser()----------"
);
14
. }
15
.
16
.
public
void
findUser(
int
userId)
17
. {
18
. System.out.println(
"--------UserManagerImpl.findUser()----------"
);
19
. }
20
.
21
.
public
void
modifyUser(
int
userId, String username, String password)
22
. {
23
. System.out.println(
"--------UserManagerImpl.modifyUser()----------"
);
24
. }
25
.}
每个方法仅仅是输出一句话。
下面我们定义一个客户端类来调用这些方法。
Java代码
1
.
package
com.szy.spring;
2
.
3
.
public
class
Client
4
.{
5
.
public
static
void
main(String[] args)
6
. {
7
. UserManager userManager=
new
UserManagerImpl();
8
. userManager.addUser(
"coolszy"
,
"kuka"
);
9
. }
10
.}
运行正常输出我们期望的结果。
下面我们需要加入安全性检查,就是调用方法前我们需要进行验证,比较常见的就是权限验证,验证用户是否拥有权限,
比较常见的做法就是在UserManagerImpl类中定义一个检查安全性的方法:
Java代码
1
.
public
void
checkSecurity()
2
. {
3
. System.out.println(
"--------UserManagerImpl.checkSecurity()----------"
);
4
. }
然后在每个方法中都要调用这个方法。但是这样不符合开-闭原则(Open-Closed principle,简称OCP)。因此我们可以使用代理类来实现这个功能。代理模式很显著的特征就是和目标对象的接口一致。在代理类中我们可以控制目标对象。要控制目标对象我们必须有一个目标对象的引用。为了灵活我们可以把目标对象传到方法中,而不是在方法中实例化。同时我们把安全性检查的代码也放到代理类中,在调用每个方法之前调用这个检查方法,通过代理对我们以前的类没有破坏。
Java代码
1
.
package
com.szy.spring;
2
.
3
.
public
class
UserManagerImplProxy
implements
UserManager
4
.{
5
.
private
UserManager userManager;
6
.
7
.
public
UserManagerImplProxy(UserManager userManager)
8
. {
9
.
this
.userManager = userManager;
10
. }
11
.
public
void
addUser(String username, String password)
12
. {
13
. checkSecurity();
14
.
this
.userManager.addUser(username, password);
15
. }
16
.
public
void
deleteUser(
int
userId)
17
. {
18
. checkSecurity();
19
.
this
.userManager.deleteUser(userId);
20
. }
21
.
public
String findUser(
int
userId)
22
. {
23
. checkSecurity();
24
.
return
this
.userManager.findUser(userId);
25
. }
26
.
public
void
modifyUser(
int
userId, String username, String password)
27
. {
28
. checkSecurity();
29
.
this
.userManager.modifyUser(userId, username, password);
30
. }
31
.
public
void
checkSecurity()
32
. {
33
. System.out.println(
"--------UserManagerImpl.checkSecurity()----------"
);
34
. }
35
.}
下面修改客户端类。
Java代码
1
.UserManager userManager=
new
UserManagerImplProxy(
new
UserManagerImpl());
2
. userManager.addUser(
"coolszy"
,
"kuka"
);
这样总的来说比较灵活。这个依赖关系是我们自己做的,我们完全可以交给spring处理。
按照上面的这种做法有一个缺点,如果接口中方法很多,那么我们实现每一个方法都要添加检查方法checkSecurity(),影响了我们的业务处理。采用静态代理模式我们是没法解决的,这时我们需要使用AOP思想。
Spring学习笔记(
13
)----动态代理模式分析演示
-----------------------------------------------
上一节演示的是静态代理模式,本节演示的是静态代理模式,既然是动态,那么就不存在UserManagerImplProxy类。
使用动态代理我们需要声明一个类SecurityHandler,这个类要实现InvocationHandler接口。
在类中定义一个产生动态代理的方法newProxy();同时把我们验证的代码放到这个类中。通过SecurityHandler,当我们调用方法时默认会调用SecurityHandler类invoke方法,我们在这个方法中进行安全性检查,检查通过后在调用真实的方法。需要注意的是目标对象接口中的部分方法是存在返回值的。
Java代码
1
.
package
com.szy.spring;
2
.
3
.
import
java.lang.reflect.InvocationHandler;
4
.
import
java.lang.reflect.Method;
5
.
import
java.lang.reflect.Proxy;
6
.
7
.
public
class
SecurityHandler
implements
InvocationHandler
8
.{
9
.
private
Object targetObject;
10
.
11
.
public
Object newProxy(Object targetObject)
12
. {
13
.
this
.targetObject=targetObject;
14
.
//返回动态代理
15
.
return
Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
16
. targetObject.getClass().getInterfaces(),
17
.
this
);
18
. }
19
.
public
Object invoke(Object proxy, Method method, Object[] args)
20
.
throws
Throwable
21
. {
22
. checkSecurity();
23
. Object ret=
null
;
24
.
try
25
. {
26
.
//调用目标对象的真实方法
27
. ret=method.invoke(
this
.targetObject, args);
28
.
//ret接受存在的返回值,不存在返回值则为Null
29
. }
catch
(Exception e)
30
. {
31
. e.printStackTrace();
32
. }
33
.
return
null
;
34
. }
35
.
public
void
checkSecurity()
36
. {
37
. System.out.println(
"--------UserManagerImpl.checkSecurity()----------"
);
38
. }
39
.}
使用这种方式维护起来相对比较好,我想进行安全性检查就进行,不想就不进行,很方便。
下面进行客户端调用
Java代码
1
.
package
com.szy.spring;
2
.
3
.
public
class
Client
4
.{
5
.
public
static
void
main(String[] args)
6
. {
7
. SecurityHandler handler=
new
SecurityHandler();
8
.
//创建代理对象
9
. UserManager userManager=(UserManager)handler.newProxy(
new
UserManagerImpl());
10
. userManager.addUser(
"coolszy"
,
"kuka"
);
11
. }
12
.}
转载地址:http://hsfbi.baihongyu.com/